بایگانی نویسنده: علی یوسفی

ماکرو ها در لاراول macro in laravel

ماکرو در واقع امکانی هست که متوانیم رفتار یک کلاس را در زمان اجرا تغییر دهیم . با اضافه کردن یک متد به کلاس.
یه مثال :

در فایل AppServiceProvider در متد بوت کد زیر را مینویسیم.

    public function boot()
    {
        Response::macro('hi', function ($name) {
            return 'Hi ' . $name ;
        });
    }

و الان می میتوانیم متد تعریف شده را روی کلای Response صدا بزنیم.
در فایل web کد زیر را مینویسیم .

use Illuminate\Support\Facades\Response;
Route::get('macro', function () {
    echo Response::hi('Ali');
    echo ' ';
    echo response()->hi('Ali');
});

خروجی

//localhost:8000/macro
Hi Ali Hi Ali

مثال های بیشتر از راهنمای لاراول
https://laravel.com/docs/8.x/collections#extending-collections
https://laravel.com/docs/8.x/responses#response-macros
https://laravel.com/docs/8.x/scout#builder-macros
سوال پیش میاد چه نیازی هست به این کار؟
پاسخی که من به ذهنم میرسه، اگه یه کار تکراری رو توی یه کلاس انجام میدیم میتونیم اون رو یک بار به عنوان ماکرو به کلاس اضافه کنیم و بعدا بارها از اون استفاده کنیم، و کمک میکنه کد کمتر بنویسیم و کد کمتر هم یعنی باگ کمتر. اگه از ماکرو استفاده نکنیم از چی می‌تونیم استفاده کنیم؟
از ارث بری :
از تریت ها :
از متدهای کمکی(helpers) :
همه اینها کمک میکنن کد کمتر بنویسیم اما خوبی ماکرو اینه که میتونیم رفتار کلاس های موجود رو در زمان اجرا runtime تغییر بدیم.
آیا میتوانیم همه کلاسها را تغییر دهیم ؟‌
خیر، فقط کلاسهایی که Macroable هستند.

با جستجوی Macroable در کد لاراول کلاس های پیش فرض که در لاراول به صورت ماکروابیل تعریف شده اند،‌را میتوانید مشاهده کنید.  (یک لیست هم اینجا هست)

یک کلاس ماکروابیل تعریف کنیم.

<?php

namespace App\Services;

use \Illuminate\Support\Traits\Macroable;

class Person {
    use Macroable;

    private $name;

    public function __construct($name) 
    {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

و در متد بوت پروایدر یک ماکرو ساده تعریف میکنیم.

class <a href="https://github.com/spatie/macroable">AppServiceProvider</a> extends ServiceProvider
{
    public function boot()
    {
        \App\Services\Person::macro('hi', function() {
            return 'Hi ' . $this->getName();
        });
    }
}

و آن متد را روی کلاس اجرا میکنیم.

// http://localhost:8000/person
Route::get('person', function () {
    $person = new \App\Services\Person('Ali');
    echo $person->hi(); // use macro
    // Hi Ali
});

می بینیم که به راحتی میتوانیم کلاس ها را ماکروابل تعریف کنیم و آنها را گسترش دهیم. با نگاهی به تریت ماکروابیل،  میبینیم که از reflection ها استفاده میکند.

میتوانیم برای خودمان متد های پرکاربرد را ذخیره کنیم و دفعه بعد به صورت ماکرو آنها را تعریف کنیم. 🙂
البته حواسمون هست که ماکرو رو میتونیم در سرویس پروایدرهای دیگری غیر از <a href="https://github.com/spatie/macroable">AppServiceProvider</a> تعریف کنیم، و اسم های خوانا تری هم برای آنها انتخاب کنیم.
یک پکیج نمونه که قابلیت های لاراول رو با ماکرو ها توسعه داده
https://github.com/spatie/macroable

فایل ها

متد های HTTP یا HTTP methods ، verbs

HTTP methods یا verbs
۱- GET

retreive data from a server at the specified resource

برای دریافت اطلاعات استفاده میشود.

تنها درخواستی است که فقط داده را درخواست میکند و هیچ منبعی را تغییر نمیدهد.
۲- POST

send data to the API sever to create or udpate a resource.

داده ارسالی در بدنه درخواست request body ارسال می شود.

درخواست پست non-idempotent است.
۳ – PUT

send data to the API to create or update a resource

PUT requests are idempotent

اگر یک درخواست put چندین ارسال شود همیشه یک نتیجه را حاصل میشود. در خواست پست ممکن است تاثیرات جانبی (side effect) داشته باشد و ممکن است یک ریسورس چندین بار ایجاد شود.
۴ – PATCH

only apply partial modifications to the resource.

فقط بخشی از یک منبع را تغییر میدهد.

پچ همانند پست ایدمپوتنت نیست.

پچ برای بروزرسانی بخشی از ریسورس استفاده می شود یعنی ریسورس از قبل وجود دارد و لازم نیست مثل پوت و پست همه داده ها را ارسال کنیم.

۵ – Delete

برای حذف یک ریسورس استفاده میشود. همان گونه از اسمش پیداست.
۶- HEAD

شبیه به متد GET است با این تفاوت که در پاسخ هیچ بدنه ای دریافت نمی کند .

برای دانلود فایل های حجیم میتواند کاربرد داشته باشد.

برای تست دود هم می تواند استفاده داشته باشد.

اگر هم سرور بی توجه به نوع درخواست چیزی را برگرداند باز هم فقط بخش head دیده می شود.

سوال : می توانیم با بریک پوینت یک درخواست هد را تریس کنیم؟

جواب : بله می توانیم و کد زیر را تا آخر اجرا می کند و فقط مقدار هدر دریافت می شود.

۷ – OPTIONS

return data describing what other methods and operations the server supports

PATCH no no
Idempotent methods : به معنای این است که چه یک بار و چه ده بار آن را صدا بزنیم یک خروجی تاثیر آن بر روی منبع یکسان باشد.

رفلکشن در پی اچ پی Reflection in PHP بخش دوم

در قسمت قبل دیدیم که با رفلکشن ReflectionFunction می‌توانیم اجزای یک تابع را بررسی کنیم و پارامتر‌های تابع هم از نوع رفلکشن ReflectionParameter هستند و میتوان اجزای آنها را هم بررسی کرد. در این بخش یک کلاس تعریف میکنیم و آن را بررسی میکنیم.
ابتدا یک کلاس به نام Person را تعریف میکنیم

<?php
 /** * This is simple description about class * */
 class Person 
{
 public $name;
 private $age;

 public function __construct()
   {
      $this->name = 'Anonymous';
   }

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setAge($age)
    {
        $this->age = $age;
    }

    public function getAge()
    {
        return $this->age;
    }
}

$rc = new ReflectionClass('Person');

echo $rc->getName(); // Person  
// نام کلاس را بر میگرداند

// echo $rc->getDocComment();
// /**
// * This is simple description about  class 
// *
// */

// توضیحات بالای کلاس را برمیگرداند 

$methods = $rc->getMethods();
// print_r($methods); 
//   هستند ReflectionMethod لیستی از متد های تابع را برمیگرداند که از نوع 
foreach ($methods as $method) {
    echo $method->getName(); 
    //    دقت میکنید که به یک ابجکت از نوع رفلکشن متد دسترسی داریم و از توابع مربط به خودش میتوانیم استفاده کنیم 
    echo "\n";
}

همان گونه که در کد بالا می بینبد می توانیم اجزاء کلاس و ساختار هر بخش آن را بررسی کنیم و نام کلاس getName و با استفاده از متد getMethods متد های کلاس را ببینیم که این متد برای یک آرایه از نوع ReflectionMethod بر می‌گرداند.
ReflectionMethodساختاری شبیه به ReflectionFunction دارد و  هر دو اینها از کلاس ReflectionFunctionAbstract ارث بری کرده اند

ReflectionFunctionAbstract implements Reflector
ReflectionFunction extends ReflectionFunctionAbstract implements Reflector
ReflectionMethod extends ReflectionFunctionAbstract implements Reflector

کلاس ReflectionFunctionAbstract شامل متد های زیر است

final private __clone ( void ) : void
public getClosureScopeClass ( void ) : ReflectionClass
public getClosureThis ( void ) : object
public getDocComment ( void ) : string
public getEndLine ( void ) : int
public getExtension ( void ) : ReflectionExtension
public getExtensionName ( void ) : string
public getFileName ( void ) : string
public getName ( void ) : string
public getNamespaceName ( void ) : string
public getNumberOfParameters ( void ) : int
public getNumberOfRequiredParameters ( void ) : int
public getParameters ( void ) : array
public getReturnType ( void ) : ReflectionType
public getShortName ( void ) : string
public getStartLine ( void ) : int
public getStaticVariables ( void ) : array
public hasReturnType ( void ) : bool
public inNamespace ( void ) : bool
public isClosure ( void ) : bool
public isDeprecated ( void ) : bool
public isGenerator ( void ) : bool
public isInternal ( void ) : bool
public isUserDefined ( void ) : bool
public isVariadic ( void ) : bool
public returnsReference ( void ) : bool
abstract public __toString ( void ) : void

ReflectionFunction متد های بالا را دارد اما ReflectionMethod متد های زیر  را علاوه بر متد های بالا دارد

public static export ( string $class , string $name [, bool $return = FALSE ] ) : string
public getClosure ( object $object ) : Closure
public getDeclaringClass ( void ) : ReflectionClass
public getModifiers ( void ) : int
public getPrototype ( void ) : ReflectionMethod
public invoke ( object $object [, mixed $... ] ) : mixed
public invokeArgs ( object $object , array $args ) : mixed
public isAbstract ( void ) : bool
public isConstructor ( void ) : bool
public isDestructor ( void ) : bool
public isFinal ( void ) : bool
public isPrivate ( void ) : bool
public isProtected ( void ) : bool
public isPublic ( void ) : bool
public isStatic ( void ) : bool
public setAccessible ( bool $accessible ) : void

با نگاهی متد های اضافه می بینم چه ویژگی هایی یک متد را از فانکشن متمایز میکند.

ایده :‌ به لیست متد ها نگاه کنید  و فکر کنید هر کدام چه کاربردی دارند یا اینکه کدام با کاربرد کدام آشنا نیستید.

به متد setAccessible دقت کنید، آیا  واقعا میتوانیم دسترسی یک متد را تغییر دهیم ؟ (بررسی می‌کنیم)

یک کلاس تعریف میکنیم که یک متد private هم داشته باشد.

<?php

class Math 
{
    public static function power($num)
    {
            return "Power {$num} is " . self::calcPower($num);
    }

    private static function calcPower($num)
    {
        return $num * $num;
    }
}

echo Math::power(2);
// Power 2 is 4

// echo Math::calcPower(2);
// PHP Fatal error:  Uncaught Error: Call to private method Math::calcPower() from context ''

همان طور که انتظار داریم متد private را نمی توانیم خارج از خود کلاس صدا بزنیم(دسترسی نداریم)، اما با استفاده از رفلکشن می توانیم این کار را انجام دهیم

$rm = new ReflectionMethod('Math', 'calcPower');

$rm->setAccessible(true);

echo  $rm->invoke(null, 2); // صدا زدن متد استاتیک
// ۴

با استفاده از setAccessible و invoke توانستیم یک متد private  را خارج از کلاس صدا بزنیم. (جالب بود نه)

برای پروپرتی هم ReflectionProperty داریم و می توانیم دسترسی ها را تغییر دهیم و از آنها هم استفاده کنیم.

در پایین لیست رفلکشن ها را و کلاس ها و اینترفیس های مربوط به رفلکشن‌ها را میبینیم که می توانیم یک دید کلی در مورد آنها پیدا کنیم.

Reflector 
 ReflectionClassConstant implements Reflector
 ReflectionProperty implements Reflector
 ReflectionClass implements Reflector
 ReflectionObject extends ReflectionClass implements Reflector

 ReflectionZendExtension implements Reflector
 ReflectionExtension implements Reflector 

 ReflectionFunctionAbstract implements Reflector 
 ReflectionFunction extends ReflectionFunctionAbstract implements Reflector 
 ReflectionMethod extends ReflectionFunctionAbstract implements Reflector
 
 ReflectionType 
 ReflectionNamedType extends ReflectionType

 ReflectionParameter implements Reflector 
 
 ReflectionGenerator 
 Reflection
 ReflectionException extends Exception

احتمالا بررسی ReflectionObject هم جالب خواهد بود. (تمرین)

فایل های این بخش

در بخش بعد در مورد کاربرد رفلکش‌ها می نویسم و بحث رفلکشن را تمام میکنیم.

 

رفلکشن در پی اچ پی Reflection in PHP

رفلکشن قابلیتی در یک برنامه کامپیوتر است که میتوان ساختار و رفتار خود برنامه در زمان اجرا را بررسی کرد و تغییر داد.
طبق تعریف php.net : رفلکشن به ما قابلیت مهندسی معکوس کلاس ها، اینترفیس ها، توابع، متد ها و اکستنشن ها را میدهد به این معنی که بدانیم چه قابلیت هایی دارد. بعلاوه میتوان برای دریافت راهنمای (doc comments) کلاس ها، متدها و فانکشن ها از رفلکشن استفاده کرد.
این قابلیت از نسخه ۵.۶ به php اضافه شده است.

برای شروع چند دستور را که با این قابلیت در php  وجود دارد را بررسی میکنیم

$ php --rf strlen اطلاعات تابع
$ php --rc finfo اطلاعات کلاس
$ php --re json اطلاعات اکستنشن
$ php --ri dom اطلاعات کانفیگ اکستنشن

با اجرای php –rf strlen

Function [ <internal:Core> function strlen ] {
   - Parameters [1] {
         Parameter #0 [ <required> $str ]
    }
}

اطلاعاتی که به ما میده این است که تابع مربوط به هسته اصلی php  است و تعداد پارامتر های آن یکی است و آن پارامتر هم اجباری است. برای مقایسه میتوان خروجی های توابع دیگر را هم دید.

php --rf json_encode
php --rf sprintf

و همچنین با با دستورات بالا میتوان اطلاعات کاملی در مورد تابع، کلاس، اکستنش و کانفیگ اکستنشن دریافت کرد. یعنی میتوان اطلاعاتی در مورد کلاس به دست آورد

php --rc DateTime
Class [  class DateTime implements DateTimeInterface ] {

  - Constants [13] {
    Constant [ public string ATOM ] { Y-m-d\TH:i:sP }
    ...
  }

  - Static properties [0] {
  }

  - Static methods [3] {
    Method [  static public method __set_state ] {
    }
    ...
  }

  - Properties [0] {
  }

  - Methods [15] {
    Method [ <internal:date, ctor> public method __construct ] {

      - Parameters [2] {
        Parameter #0 [ $time ]
        Parameter #1 [ $timezone ]
      }
    }
    ...
  }
}

اطلاعات کاملی از کلاس DateTime به ما میدهد از تعداد ثابت ها و پروپرتی ها و متد های استاتیک و سایر متد ها و برای هر متد و پروپرتی هم اطلاعات کلی از آن به ما می دهد.

برای اطلاعات اکستنشن و کانفیگ اکستنشن ها هم می توانیم از دستورات بالا استفاده کنیم و جزئیات آنها را بررسی کنیم.

خوب حالا برای کلاس ها و توابعی که خودمون تعریف کردیم باید چه کنیم ؟ (با یه پرش بلند خودمون رو به اعماق رفلکشن می رسونیم 🙂 )

ابتدا یک تابع می نویسیم

<?php
 /**
 * Echo bar
 */
 function hello($name = 'World') : string
 {
    return 'Hello ' . $name . "\n";
 } 
// echo hello();

 $rf = new \ReflectionFunction('hello');
 echo $rf->getName(); 
// hello
echo $rf->getStartLine();
// ۶ 
echo $rf->getEndLine();
// ۹
echo $rf->getFileName();
// /home/user/Desktop/Reflection/function.php

echo $rf->getShortName(); 
// hello

echo $rf->getNamespaceName(); 
// hello

echo $rf->getDocComment(); 
// /**
//  * Echo  bar
//  */

echo $rf->getReturnType();
// string

print_r($rf->getParameters());
/*
    (
        [۰] => ReflectionParameter Object
            (
                [name] => name
            )
    )
*/

با استفاده از کلاس ReflectionFunction توانستیم کلی اطلاعات از یک فانکشن دریافت کنیم. از نام تابع، تا لاین شروع و پایان و فایلی که در آن وجود دارد و return type و … . حتی توانستیم کامنتی که خودمان نوشته بودیم هم دریافت کنیم.
و با کمی کنجکاوی می توانید اطلاعات بامزه دیگری هم با خواندن راهنمای کلاس ReflectionFunction پیدا کنید.

کاربرد :  اگر از لاراول استفاده میکنید و دوست دارید بدانید تابع dd یا config در کدام فایل تعریف شده اند می تواند از این رفلکشن استفاده کنید.

به خروجی پارامتر ها دقت میکنید، یک پارامتر از نوع ReflectionParameter دارد و نام آن name است و خود یک آبجکت است که می توانیم خود پارامتر را هم دوباره بررسی کنیم (با رفلکشن مهندسی معکوس انجام بدیم). جالبه نه می توانیم ببینیم یک پارامتر فانکشن در php چه ویژگی هایی دارد 🙂 . و به همین صورت برای کلاس و ثابت ها و پروپرتی ها، نوع ها و ابجکت و … هم رفلکشن داریم.

ایده : با کنجکاوی کردن در اعماق رفلکشن ها می توانیم بفهمیم چقدر ساختار OOP  در PHP  را مسلط هستیم و با مفاهیم جالبی برخورد میکنیم که ارزش وقت گذاشتن دارد.

کلاس های تعریف شده برای رفلکشن کلاس ها، متد ها و …

Reflector
ReflectionClassConstant implements Reflector
ReflectionProperty implements Reflector
ReflectionClass implements Reflector
ReflectionObject extends ReflectionClass implements Reflector

ReflectionZendExtension implements Reflector
ReflectionExtension implements Reflector

ReflectionFunctionAbstract implements Reflector
ReflectionFunction extends ReflectionFunctionAbstract implements Reflector
ReflectionMethod extends ReflectionFunctionAbstract implements Reflector

ReflectionType
ReflectionNamedType extends ReflectionType

ReflectionParameter implements Reflector

ReflectionGenerator
Reflection
ReflectionException extends Exception

در پست بعدی در مورد ReflectionClass  و ReflectionObject این بحث را ادامه می دهیم.

فایل های این بخش

منبع و مطاله بیشتر https://www.php.net/manual/en/book.reflection.php

چارت Nassi–Shneiderman diagram NSD

معرفی

    چارت ناسی-شنیدرمن یاNSD برای نمایش تصویری ساختار برنامه‌نویسی استفاده می‌شود. و توسط Isaac Nassi و Ben Shneiderman دو در سال ۱۹۷۲ توسعه داده شده است. همچنین به این چارت structograms (چارت‌ساختار) می‌گویند که ساختار برنامه را نمایش می‌دهد.

    طبق طراحی حل مساله  بالا به پایین  مسئله را کوچکتر و کوچکتر می‌کنیم تا در نهایت چیزی که باقی می‌ماند عبارت های ساده و ساختارهای کنترلی هستند. چارت NSD  این مساله ها را مستقیما نمایش میدهد با تجزیه کردن مساله به زیرمساله ها و در این چارت زیر مساله ها با باکس های تودرتو نمایش داده می شود. مطابق با فلسفه برنامه نویسی ساختار یافته هیچ نوع نمایشی  برای استفاده از goto  در این چارت وجود ندارد. از این چارت به ندرت در برنامه نویسی استفاده میشود. در سطح انتزاعی نزدیک به کد ساختار یافته است و برای ویرایش باید کل ساختار را دوباره بکشیم. با یان وجود یان جارت برای طرح اولیه پروسه ها و طراحی در سطوح بالا مفید است.

    چارت NSD تقریبا شبیه و قابل مقایسه با فلوچارت است. هر چیزی را که در NSD می‌توان نشان داد در این فلوچارت هم قابل نمایش است و برعکس. استثنا هایی هم مانند عبارت  goto و عبارت های break , continue  در حلقه ها وجود دارد که در چارت NSD  قابل پیاده سازی نیستند.

نمودارها

    Process blocks: بلوک های فرایند

بلوک های فرایند نمایشی از ساده ترین گاه ها هستند و نیازی به آنالیز ندارند. وقتی به نوع بلوک رسیدیم کارهای داخل بلوک را انجام میدهیم و به بلوک بعدی میرویم.

Branching blocks: بلوک‌های شاخه (انتخاب)

    دو نوع شاخه بندی داریم . نوع اول صحیح / غلط یا بله/خیر که دو مسیر برای ادامه اجرای برنامه وجود دارد و بسته به اینکه شرط درست است یا خیر یکی از دو مسیر  انتخاب میشود. این بلوک‌ها می توانند در حلقه کارهایی را انجام دهند تا زمانی که شرط خاصی برقرار باشد.

   نوع دوم می‌تواند چندین شاخه برای انتخاب داشته باشد. این بلوک زمانی که چندین خالت برای انتخاب وجود داشته باشد استفاده میشود. معمولا شامل یک پرسش یا انتخاب از بین چند مورد هستند.


Testing loops: حلقه های شرط

    این بلوک برای اجرا کردن یک یا چند دستور در حلقه استفاده می‌شود تا زمانی که شرط خاصی برقرار باشد.  این بلو های پردازشی توسط حلقه ها پوشش داده میشوند و زیر مجموعه‌ای هستند که شرط ها انها را با نوار جانبی جدا کرده اند.

   دو نوع داریم، اول تست و آخر تست.  تنها تفاوت آنها در مواجه‌شدن با این است که کدام گام ها انجام میشود. در حالت اول وقتی برنامه به شرط میرسد  ابتدا چک میکند آیا شرط برقرار است، آنگاه، اگر فرایند در حلقه کامل نشده است و انگاه حلقه بر‌میگردد. تست دوباره اجرا میشود و اگر هنوز شرایط برقرار نباشد دوباره پروسه تکرار می‌شود. اگر هر یک از بخش‌های شرط‌ برقرار باشد برنامه اجرای پروسه بلوک را خاتمه داده و بلوک بعد اجرا می‌شود.

    برای حالت دوم کاملا برعکس حالت قبل است. فرایند های بلاک ابتدا اجرا میشوندو در آخر شرط بررسی می‌شود. در این حالت دستورات درون بلوک حداقل یک بار اجرا می‌شوند.

 Concurrent همزمان

طبق شکل زیر میتواند اجرا شوند.

File:NassiShneiderman-Parallel.svg

منبع : ویکی‌پدیا NSD

تابع serialize & unserilaze

تابع serialaze یک مقدار php که کلاس هم می تواند باشد را به صورت رشته و قابلیت ذخیره‌سازی در پایگاه داده تبدیل میکند و تابع unserilaze هم مقدار serilize شده را به آبجکت یا مقدار قبلی باز میگرداند . در کد زیر یک کلاس را ذخیره میکنیم و بازمیگردانیم.


<?php class Test { public $msg; public function __construct($msg) { $this->msg = $msg;
    }

    public function say()
    {
        echo $this->msg;
    }
}

$t = new Test('Hi User ');
$t->say(); // Hi User

$store = serialize($t);

$t = null;

echo "\n", $store, "\n"; // O:4:"Test":1:{s:3:"msg";s:8:"Hi User ";}

$ut = unserialize($store);
echo gettype($ut); // object
var_dump($ut); // class Test

$ut->say(); // Hi User

/*
Hi User
O:4:"Test":1:{s:3:"msg";s:8:"Hi User ";}
object/home/userx/Desktop/ex1/ser.php:29:
class Test#1 (1) {
public $msg =>
string(8) "Hi User "
}
Hi User
*/

late-static-bindings چیست ؟

کلمه کلیدی self روال طبیعی ارث بری پیش نمی برد و همیشه self به کلاسی که در آن قرار دارد اشاره می کند. و این یعنی اینکه اگر در کلاس پدر با استفاده از self متد استاتیکی را صدا زده باشید و در کلاس فرزند بخواهید از متد فرزند استفاده کنید، نمی توانید و همان متد پدر را صدا میزند.


 class A 
{
	public static function getName() { return 'Car'; }
	public static function showName() { echo self::getName(); }
}

class B extends A {
	public static function getName() { return 'BMW'; }
}

A::showName(); // Car
B::showName(); // Car

راه حل ۱ : تکرار متد در کلاس فرزند


 class A 
{
	public static function getName() { return 'Car'; }
	public static function showName() { echo self::getName(); }
}

class B extends A {
	public static function getName() { return 'BMW'; }
	public static function showName() { echo self::getName(); }

}

A::showName(); // Car
B::showName(); // BMW

راه حل دوم : استفاده از متد get_called_class


 class A 
{
	public static function getName() { return 'Car'; }
	public static function showName() { 
		$class = get_called_class();
		echo $class::getName(); 
	}
}

class B extends A {
	public static function getName() { return 'BMW'; }
}

A::showName(); // Car
B::showName(); // BMW

راه حل سوم : برای رفع این مشکل کلمه کلیدی جدیدی به نام static استفاده می کنیم.


 class A 
{
	public static function getName() { return 'Car'; }
	// public static function showName() { echo self::getName(); } 
	public static function showName() { echo static::getName(); } 
}

class B extends A {
	public static function getName() { return 'BMW'; }
}

A::showName(); // Car
B::showName(); // BMW

هنگامی که از self استفاده می کنیم در زمان کامپایل مقدار را جایگذاری میکند ولی زمانی که از static استفاده می کنیم در زمان اجرا مقدار را جای گذاری می کند. استفاده از روش سوم را last static binding می گوییم.

منابع :

https://stackoverflow.com/questions/1912902/what-exactly-are-late-static-bindings-in-php

https://codeinphp.github.io/post/late-static-binding-in-php/

http://ir2.php.net/language.oop5.late-static-bindings

Primary , Secondary و بعدی چی میشه ؟

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

Primary, Secondary, Tertiary, Quaternary, Quinary, Senary, Septenary, Octonary, Nonary, and Denary, – , Duodenary.

جالبه برای عدد یازده چیزی نداشتن ولی برای عدد محبوب دوازده وجود داشته.

معنی اینها چی میشه و توی فارسی ما چی معنی می کنیم ؟

با کمک ترجمه گوگل :

Primary  : اولیه، ابتدایی، اصلی
Secondary:  ثانویه، دوم، فرعی
Tertiary : ثالث، دوران سوم، قسمت سوم، سومین
Quaternary: چهارتایی، چهار واحدی
Quinary: پنج پنجی
Senary: شش تایی
Septenary: هفت هفتی
Octonary: هشت هشتی(خودم به گوگل پیشنهاد دادم)
Nonary: نُه ُنهی(پیشنهاد خودم)
Denary : ده دهی (پیشنهاد خودم)
Duodenary : دوازدهه

در این بین یه چنین متنی هم دیدم گفتم همین جا بذارم که پیشنهاد گوگل برای senary بود.
Base 2 is called binary, Base 3 is called ternary, Base 4 is called quaternary, Base 5 is called quinary, Base 6 is called senary , Base 7 is called septenary, Base 8 is called octonary or octal.
خوب میشه اینها رو مبنای x  هم ترجمه کرد مثلا مبنای هفت. ولی به نظر میرسه به مجموعه پشت سر هم به اون تعداد رو از این روش شماره گذاری میکنن . مثلا دو تا دوتا و سه تا سه تا که همون معنای مبنا در ریاضی رو میده.
برای تلفظ بهتره از این سایت نگاه کنیم  و اطلاعات بیشتر مثلا برای چهارمی  .
منبع پیدا کردن این عدد ها پشت سر هم : لینک
مثل اینکه برخی دوره های زمین شناسی رو هم با همین ها نام میبرند.
دو تای اول خیلی استفاده میشن و بقیه به ندرت اسفاده میشن. مثلا فایر فاکس تا چهارمی رو توی دیکشنری برای پیدا کردن غلط املایی داره و برای بقیه کلمات رو نمیشناسه.

autoloading in php اتولودینگ در php

پ ن : این مطلب برای یاداشت کردن آموخته های خودم در مورد Autoloading است و ساختار آموزشی ندارد.

اوتولودینگ به مبحث لود شدن خودکار فایل ها می پردازد به این معنا که هنگامی که فایل ها زیاد باشند و بخواهیم از آنها استفاده کنیم قبل از هر بار استفاده باید آنها را require کنیم و سپس از آن استفاده کنیم، وقتی تعداد فایل ها زیاد باشد مدیریت این کار سخت و پیچیده میشود، زیرا می خواهیم در هر بار پردازش کمترین تعداد فایل یا درست تر فقط تعداد فایل هایی که نیاز داریم را لود کنیم نه اینکه همه فایل ها را لود کنیم . یعنی اگر کاربر بخواهد مثلا یک فایل را آپلود کند فقط فایل های مربوط به آپلود لود شود و سایر فایل ها مانند فایل هایی برای نمایش تصویر لود نشوند. مزیت این کار مدیریت استفاده از رم و افزایش سرعت پردازش خواهد بود.

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

برای نوشتن کد به صورت شی گرایی (قانون نانوشته) به ازای هر کلاس یک فایل با نام کلاس ایجاد می کنیم . مثلا اگر قرار است کلاس Hello را بنویسم یک فایل هم با نام Hello.php ایجاد می کنیم و این کلاس را در همین فایل تعریف میکنیم.

دو کلاس داریم به نام Linux و Windows و هر کدام متدی به نام say دارند که یک نام سیستم عامل را چاپ میکند.

روش سنتی برای لود کردن کلاس ها :

Linux.php


namespace Os;
class Linux 
{
public function say() { echo "Linux\n"; }
}

Windows.php


 namespace Os;
 class Windows {
 public function say() { echo "Windows\n"; }
 }
 

index.php


require "./Os/Linux.php";
require "./Os/Windows.php";

$os1 = new Os\Linux();
$os1->say(); // Linux

$os2 = new Os\Windows();
$os2->say(); // Windows

 

روش استفاده از اتولودینگ :‌ برای این کار معمولا یک کلاس اتولودینگ تعریف میکنیم و در آن متدی تعریف میکنیم که با استفاده از متد spl_autoload_register می تواند نام کلاس ها را تشخیص دهد و هر زمان که بخواهیم یک کلاس را new کنیم (یک نمونه از کلاس ایجاد کنیم) خودش آن کلاس را لود می کند.

Autoload.php


class Autoload
{
 public function load($className)
 {
   $file = __DIR__ .'/'. str_replace('\\', '/', $className) . '.php';
   if (file_exists($file)) {
    require $file;
   } else {
   return false;
   }
 }
 public function register()
 {
  spl_autoload_register([$this, 'load']);
 }
}

$loader = new Autoload();
$loader->register();

index.php


require "./Autoload.php";

$os1 = new Os\Linux();
$os1->say(); // Linux

$os2 = new Os\Windows();
$os2->say(); // Windows

الان اگر کلاس Mac را هم در پوشه Os اضافه کنیم به صورت خودکار لود می شود و می توانیم از آن استفاده کنیم.

دانلود فایل Autolader.zip

منابع :‌
http://ir2.php.net/autoload
http://phpbridge.org/intro-to-php/autoloading