برچسب: آموزش php

  • استاندارد PSR-1 در PHP

    یسری نکات تو کد نویسی تو هر زبانی هستن که رعایت کردنشون میتونه شما رو خیلی حرفه ای تر نشون بده و رعایت نکردنشون زیاد جالب نیست برای یک برنامه نویس که ادعای خفن بودن میکنه 🙂

    تو زبان PHP یسری استاندار تعریف شده که امروزه همه برنامه نویسای خوب PHP رعایتش میکنن، این میتونه برای همه خوب باشه… هم کسی که کد مینویسه و هم کسی که کد میخونه.

    استانداردی که تو این پست میخام بصورت خلاصه در موردش حرف بزنم PSR-1 هست که اشاره میکنه استاندارد های پایه ی کد نویسی در PHP.

     

    تو PHP چند روش برای باز کردن کد PHP و بستن اون وجود داره ولی این استاندارد میگه که از این روش استفاده کنید :‌<?php ?> یا از نوع کوتاهش به این صورت :‌ <? =?>

    کاراکتر انکودینگی که استفاده میشه باید UTF-8  باشه و بدون BOM .

    نکته ی دیگه ای که خیلی مهمه اینه که اجرای منطق برنامه با include  و تعریف کردن تابع و… یک جا نباشن، یعنی مثلا شما اگه دارید یه فانکش تعریف میکنید بالاش مثلا echo  نکنید. این مثالی که در زیر اومده یه نمونه غلط طبق این استاندارد هست :

    <?php
    // side effect: change ini settings
    ini_set('error_reporting', E_ALL);
    
    // side effect: loads a file
    include "file.php";
    
    // side effect: generates output
    echo "<html>\n";
    
    // declaration
    function foo()
    {
        // function body
    }

    ولی در مثال زیر استاندار PSR-1 بخوبی رعایت شده :

    <?php
    // declaration
    function foo()
    {
        // function body
    }
    
    // conditional declaration is *not* a side effect
    if (! function_exists('bar')) {
        function bar()
        {
            // function body
        }
    }

    namespace ها و نام کلاس ها

    هر کلاس باید توی یه فایل نوشته بشه و مثلا وسط کد کلاس تعریف نکنید و یا مثلا دو تا کلاس رو توی یه فایل ننویسید. اسم کلاس ها باید بصورت StudlyCaps باشه که مشخصه ینی چجوری…

    برای ورژن ۵٫۳ به بعد از روش رسمی فضای نام ها استفاده کنید، برای مثال :‌

    <?php
    // PHP 5.3 and later:
    namespace Vendor\Model;
    
    class Foo
    {
    }

    ولی برای ورژن های قبل که از این قابلیت پشتیبانی نمیکنن از pseudo-namespacing استفاده کنید که یه پیشوند Vendor_ به اسم کلاسها اضافه میشه و sub namespace ها بعد از اون نوشته میشن و در نهایت نام کلاس نوشته میشه :

    <?php
    // PHP 5.2.x and earlier:
    class Vendor_Model_Foo
    {
    }

    ثابت ها در کلاس ها 

    ثابت ها در کلاسها طبق این استاندارد باید با حروف بزرگ تعریف بشن و برای جدا کردن از underscore  استفاده کنید. یچیزی مثل کد زیر :

    <?php
    namespace Vendor\Model;
    
    class Foo
    {
        const VERSION = '1.0';
        const DATE_APPROVED = '2012-06-01';
    }

    در مورد پراپرتی ها در کلاس ها دستور خاصی گفته نشده ولی کلاس ها باید بصورت camelCase()  تعریف بشن.

    همین روزا بقیه استاندارا رم میتویسم واستون که بخونیم و رعایت کنیم. مرسی 🙂

     

  • file_get_content بوسیله curl در php

    همونطور که میدونید تابع flie_get_contents()  سورس فایل مورد نظر رو که میتونه حتی یک صفحه وب باشه رو میریزه توی یه رشته و میتونید هر بلایی سرش بیارید(مثلا با html-dom-parser به المنت هاش دسترسی پیدا کنید). بعضی وقتا ssl و… نمیذارن که بصورت مستقیم به محتویات صفحه دسترسی پیدا کنید. همینطور وقتی میخواید یه عکس رو از یه صفحه ای که ssl روش هست کپی کنید…  من به این مشکل برخوردم و با curl مشکلم رو حل کردم… جمع و جورش رو براتون در قالب یه فانکشن گذاشتم که امیدوارم به دردتون بخوره…

     function file_get_contents_curl( $url ) {
            $ch = curl_init();
            curl_setopt( $ch, CURLOPT_AUTOREFERER, TRUE );
            curl_setopt( $ch, CURLOPT_HEADER, 0 );
            curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
            curl_setopt( $ch, CURLOPT_URL, $url );
            curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, TRUE );
            curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 0);
            $data = curl_exec( $ch );
            curl_close( $ch );
            return $data;
        }

    موفق باشید…

  • پراپرتی و متدهای استاتیک در php

    قبل از اینکه بخوام در مورد facade  در لاراول صحبت کنم باید اطلاعات کلی در مورد توابع یا متدهای استاتیک php داشته باشید. متدهای استاتیک متدهایی از یک کلاس هستند که بدون نمونه گیری از کلاس و بصورت استاتیک قابل دسترسی هستند. یعنی بدون داشتن شئ از کلاس ، میتونیم از این نوع متدها استفاده کنیم.

    قبل از مثال در مورد متدهای استاتیک میخوام کمی در مورد متغیرها یا پراپرتی های استاتیک صحبت کنم. یک پراپرتی استاتیک بدون استفاده از $this  و به راحتی با استفاده از ::  قابل دسترسی هست. همچنین میتونید یک متغیر استاتیک رو با استفاده از کلمه کلیدی static  تعریف کنید. به مثال زیر توجه کنید :

    class test
    {
    public static $a;//Static variable
    }
    test::$a = 5;
    echo test::$a;

    میبینید که چقدر راحت میشه به پراپرتی های استاتیک دسترسی داشت. با استفاده از کلمه های کلیدی self  و parent  هم میتونید به پراپرتی های این کلاس و یا کلاس پدر دسترسی داشته باشید.

    class testParent
    {
    public static $var1;
    }
    class testChild extends testParent
    {
    public static $var2;
    public $abc =2;
    function testFunction()
    {
    self::$var2 = 3;
    parent::$var1 = 5;
    }
    }
    echo testChild::$abc; //throw fatal error

    نحوه ی تعریف متدهای استاتیک

    <?php
    class Game
    {
    	public static function start()
    	{
    		echo "Go!";
    	}
    }
    
    Game::start();

    همونطور که در بالا میبینید متد start()  بصورت استاتیک تعریف شده و خیلی شیک و مجلسی میشه ازش نمونه ساخت. این نوع توابع در نگاه اول خیلی جالب به نظر میرسن… و سوالی که پیش میاد اینه که چرا همه متد هارو استاتیک تعریف نمیکنیم؟ 

    متدهای استاتیک با اینکه اولش خیلی باحال به نظر میرسن ولی محدودیتی دارن که تنها در بعضی موارد میتونیم ازشون استفاده کنیم : “بخاطر استاتیک تعریف شدن این متدها ، امکان استفاده از $this  در این نوع متدها وجود ندارد.” ولی در مجموع این نوع متدهای خیلی پرکاربرذ هستند.

  • مفهوم و کاربرد اینترفیس – interface در PHP

    قبلا در مورد کلاسهای abstract در PHP مطلبی نوشتم ، کلاسهای انتزاعی یا abstract کلاسهایی هستند که قابل نمونه گیری نیستند و میتونیم درون کلاسهای انتزاعی متد هایی بنویسیم و در کلاسهایی که از اون مشتق شدن ازش استفاده کنیم. اینترفیس ها دقیقا مثل کلاسهای انتزاعی هستند ، با این تفاوت که در اینترفیس ها هیچ متدی نمیتونه دارای بدنه باشه. اولش خیلی عجیب به نظر میرسه… وقتی متدها بدنه نداشته باشن ، به چه دردی میخودن؟

    به خاطر داشته باشید که شما با تعریف یک متد در کلاس abstract نویسنده کلاسهای دیگه (که از این کلاس مشتق شدن) رو وادار نمیکردید که متدهای کلاس پدر رو بازنویسی کنه. ولی در اینترفیس ها اینطور هست، یعنی هر کلاسی که یک اینرفیس رو implement کنه ، باید تمام متدهای کلاس پدر رو بازنویسی کنه.

    مثلا شما میخواید کلاسی بسازید که یک تگ html رو رندر کنه و برای این کار نیاز هست که به تگ ، id و class داده بشه. شما میاید یه اینترفیس میسازید و درون اون دو تابع setID  و setClass  رو مینویسید. از اون به بعد هر کسی که کلاس خودش رو از اینترفیس شما مشتق کرد مجبوره که دو تا تابع رو بنویسه و این از خطای برنامه جلوگیری میکنه. شاید در پروژه های کوچیک زیاد به درد نخوره ، ولی پروژه هایی که تعداد زیادی توسعه دهنده روشون کار میکنند ، برای پیاده سازی design pattern ها در اکثر اوقات باید از اینترفیس ها استفاده کنن.

    نحوه ی تعریف interface ها در PHP

    برای تعریف اینترفیس ها از کلمه کلیدی interface استفاده میکنیم :

    interface abc
    {
        public function xyz($b);
    }

    در مثال بالا کلاسها رو مجبور میکنیم که متد xyz رو بنویسن. برای ارث بردن یا به اصطلاح پیاده کردن یک اینترفیس از کلمه کلیدی implements استفاده میکنیم:

    class test implements abc
    {
       public function xyz($b)
       {
           // The body of your function...
       }
    }

    نکته قابل توجه اینه که تمام متد ها و پراپرتی هایی که درون یک اینترفیس تعریف میشن باید بصورت عمومی یا public  تعریف بشن ، در غیر اینصورت با اررور مواجه میشیم.

    یک نکته دیگه اینکه یک کلاس میتونه بیش از یک اینترفیس رو implement کنه و همچنین یک اینترفیس میتونه از چند اینترفیس دیگه مشتق بشه.

    نوشتن کدهای Open-Closed با استفاده از اینترفیس ها

    ما در مفاهیم SOLID همیشه تشویق میشیم که کدهامون رو open-closed بنویسیم. ینی کدهامون برای تغییر بسته باشن و جوری کد بزنیم که کلاسها رو هی نیایم دستکاری کنیم همینطور باید کد رو جوری بنویسیم که به راحتی extendable باشه. دلیل این هم شاید برمیگرده به اینکه ریفکتور کردن کدهای اینجوری سخته و باعث بروز مشکلات میشه. من در ادامه یه مثال میارم و روی اون توضیح میدم:

    <?php
    
    interface DriverContract
    {
        public function connect();
        public function run();
        public function get();
    }
    
    
    class MySQL implements DriverContract
    {
        public function connect()
        {
            echo "Connecting to MySQL...\n";
        }
        public function run()
        {
            echo "Running MySQL...\n";
        }
        public function get()
        {
            echo "Getting MySQL...\n";
        }
    }
    
    class MongoDB implements DriverContract
    {
        public function connect()
        {
            echo "Connecting to MongoDB...\n";
        }
        public function run()
        {
            echo "Running MongoDB...\n";
        }
        public function get()
        {
            echo "Getting MongoDB...\n";
        }
    }
    
    
    function consume(DriverContract $driver)
    {
        $driver->connect();
        $driver->run();
        $driver->get();
    }
    
    consume(new MySQL());
    

    یه راه ابتدای برای نوشتن این کد اینه که بگیم اگه درایور فلان بود اینجوری کانکت شو و اگه اونیکی بود اونجوری! ولی مشکلی که پیش میاد هر بار که درایور اضافه میشه من باید بیام ایف هام رو دستکاری کنم. با این مدل کد نوشتن من انتخاب درایور رو به کانسومر واگذار کردم و در واقع پیچیدگی کد رو بردم به لایه های بالاتر و همینطور در صورت نیاز به اضافه کردن درایور دیگر، به راحتی فقط کلاسش رو عوض میکنیم و نمیریم کد قبلی رو دستکاری کنیم. در واقع ما با استفاده از یک اینترفیس اون پشت رو از دید کاربر معمولی قایم کردیم و کاربر میدونه که یه درایور رو بگیره و استفاده کنه. مثلا در فریمورک لاراول ما وقتی model binding انجام میدیم مهم نیس که اون مدل با چی ساخته شده! مهم اینه که فانکشن هایی که هر مدل میخواد رو ما داخلش داریم و اینجوریه که دیتابیس رو عوض میکنیم هیچ مشکلی پیش نمیاد. پس کد برای گسترش باز نگه داشته شده و هر چنتا درایور بخوایم میتونیم اضافه کنیم ولی برای تغییر کلوزد هست و کدهای قبلی دستکاری نمیشن.

    کدهای Testable با کمک interface ها

    اگه با مفاهیم تست نویسی و بخصوص mocking آشنا نیستید شاید این بخش یه خورده گنگ باشه واستون. ولی به هر حال در کد بالا میتونستیم بجای inject کردن اینترفیس مستقیما یک کلاس رو اینجکت کنیم و در ظاهر خیلی اتفاق بدی نمیفتاد. ولی مشکل اصلی زمانی پیش میاد که شما میخواید بدون تغییر در کد یا گرفتن ورودی اضافه کدتون رو تست کنید. اونجا برای تست تابع consume باید حتما ورودی رو از نوع مثلا MySQL میدادید که در این صورت نمیشد یه کلاس فیک برای تست نوشت ولی الان خیلی راحت میتونیم هر نمونه ای که اینترفیس رو پیاده کرده رو به عنوان ورودی به تابع بدیم و اون رو تست کنیم.

    در پایان من فرصت نکردم متن رو ریویو کنم اگه مشکلی بود ببخشید و توی کامنت ها بگید که اصلاح کنم 🙂