<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های رسول اسماعیلی</title>
        <link>https://virgool.io/feed/@RasoulEsmaeili</link>
        <description>رسول اسماعیلی - برنامه نویس</description>
        <language>fa</language>
        <pubDate>2026-04-14 18:37:05</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/158290/avatar/vrCyQz.jpg?height=120&amp;width=120</url>
            <title>رسول اسماعیلی</title>
            <link>https://virgool.io/@RasoulEsmaeili</link>
        </image>

                    <item>
                <title>بررسی تغییرات PHP 8</title>
                <link>https://virgool.io/@RasoulEsmaeili/%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1%D8%A7%D8%AA-php-8-umz9hc3fku1f</link>
                <description>HP 8ورژن 8 در تاریخ 26 Nov 2020 منتشر شد  که در این مقاله به بررسی تغییرات این نسخه خواهیم پرداخت.لیست تغییرات این نسخه:New FeaturesJITNamed argumentsAttributes (Annotations)Constructor property promotionUnion typesMatch expressionNullsafe operatorSaner string to number comparisonsConsistent type errors for internal functionsNew Classes, Interfaces, and FunctionsWeak Map classStringable interfacestr_contains(), str_starts_with(), str_ends_with()Type system and error handling improvementsAbstract trait method validationFatal error for incompatible method signaturesThe @ operator no longer silences fatal errors.Inheritance with private methodsMixed typeStatic return typeOpaque objects instead of resources for Curl, Gd, Sockets, OpenSSL, XMLWriter, and XML extensionsOther syntax tweaks and improvementsTrailing Comma in Parameter ListThrow is now an expressionAllow ::class on objectsNew FeaturesJIT(Just in Time Compiler)bayad kamel tar konm bad biaram injaNamed argumentsاین امکان فراهم شده است که بتوان پارامتر های ورودی را نامگذاری کرد و هنگام فراخوانی تابع از نام آن ها برای مقدار دهی استفاده کرد نه فقط ترتیبی که پارامتر ها تعریف شده اند.str_contains(needle: &#039;Bar&#039;, haystack: &#039;Foobar&#039;);قبل از ورودی باید اسم پارامتر را به همراه دو نقطه &quot;:&quot; ذکر کرد.Attributes (Annotations)قبلا در فریم ورک سیمفونی برای تعریف کردن هر Route برای هر متد Controller از Annotation  استفاده می شد برای مثال:class PostsController {         /**         * @Route(&amp;quot/api/posts/{id}&amp;quot, methods={&amp;quotGET&amp;quot})         */          public function get($id) { /* ... */ }}و یک کدی در فریم ورک سیمفونی نوشته شده بود که این Annotation رو می خوند و یک Route برای این کنترلر ایجاد می کرد.حالا در این نسخه این Annotation نویسی به خود زبان  php  اضافه شده و بیرون از فریم ورک Symfony هم شما میتوانید Annotation های خودتون رو بنویسید و با استفاده از PHP Reflection آن ها را بخوانید و در کد های خود از آن استفاده کنید.شکل نوشتاری Annotation ها به صورت زیر است:class PostsController {          #[Route(&amp;quot/api/posts/{id}&amp;quot, methods: [&amp;quotGET&amp;quot])]
          public function get($id) { /* ... */ }}Constructor property promotionدر این نسخه با نوشتن کد کمتری می توان property های یک کلاس را تعریف کرد و با استفاده از constructor مقدار دهی کرددر php 7:class Point {
       public float $x;
       public float $y;
       public float $z       public function __construct( float $x = 0.0, float $y = 0.0, float $z = 0.0) {
              $this-&gt;x = $x;
              $this-&gt;y = $y;
              $this-&gt;z = $z;
       }
}در PHP 8:class Point {
      public function __construct( 
              public float $x = 0.0, 
              public float $y = 0.0, 
              public float $z = 0.0){
       }
}Union typesگاهی نیاز است نوع یک متغیر یا خروجی تابع را همزمان از دو نوع مشخص کنیم این امکان در این نسخه فراهم شده است. با استفاده از پایپ &quot;|&quot; این کار رو انجام میدیم:class Number {              public function __construct( private int|float $number) {}}new Number(&#039;NaN&#039;); // TypeErrorMatch expressionساختار جدیدی به نام match در این نسخه PHP اضافه شده است که بسیار شبیه به switch case است و میتونه در آینده بخاطر کمک کردن به ساده تر و خوانا تر شده کد استفاده های زیادی داشته باشه.این ساختار جدید به عنوان ورودی یک مقدار را میگیرد و با مقادیری که دارد مقایسه میکند و در نهایت مقداری که با آن تطابق پیدا کرده است را باز میگرداند. از مزیت های match به switch می توان به مقایسه دقیق تر آن اشاره کرد که match  نوع داده ای هر دو طرف را درنظر میگیرد.echo match (8.0) { 
       &#039;8.0&#039; =&gt; &amp;quotOh no!&amp;quot,
       8.0 =&gt; &amp;quotThis is what I expected&amp;quot,
};Nullsafe operatorخیلی از مواقع نیاز است که بررسی کنیم متغیری یا مشخصه کلاسی مقداری دهی شده است یا خیر تا از آن استفاده کنیم، در این نسخه operator جدیدی معرفی شده است که در صورت استفاده از آن روی متغیری که null است به ارور null pointer exception  برخورد نمی کنیم به همین دلیل نام آن NullSafe است.برای مثال کد زیر که در هر مرحله دستیابی به دیتا null بود آن بررسی شده است:if ($session !== null) {
       $user = $session-&gt;user;
       if ($user !== null) {
              $address = $user-&gt;getAddress();
              if ($address !== null) {
                     $country = $address-&gt;country;
              }
       }
}اما کد بالا را میتوان در این نسخه به صورت ساده تر نوشت:$country = $session?-&gt;user?-&gt;getAddress()?-&gt;country;در این کد در هرکجا متغیری null باشد کد ادامه نمی دهد که به ارور null pointer بخورد مقدار null را باز میگرداند.Saner string to number comparisonsدر نسخه‌های قبلی PHP، هنگام مقایسه بین رشته‌ها و اعداد، در برخی از موارد رفتار غیر منطقی رو از PHP شاهد بودیم در این نسخه این رفتار بهبود یافته و هنگام مقایسه اعداد و رشته ها PHP رفتار دقیق تر و منطقی تری را از خودش نشون میده.برای مثال در نسخه قبلی به این صورت عمل می کرد0 == &amp;quotfoo&amp;quot   // true
0 == &amp;quot&amp;quot   // true
42 == &amp;quot42foo&amp;quot // trueاما حالا در نسخه جدید به صورت زیر عمل می کند:0 == &amp;quotfoo&amp;quot  // false
0 == &amp;quot&amp;quot    // false
42 == &amp;quot42foo&amp;quot // falseConsistent type errors for internal functionsاگر شما در حال حاضر یک تابع تعریف کنید و آرگومانی با و نوع int داشته باشد و هنگام استفاده از اون تابع ورودی با نوع دیگری مثلا string به آن بدهید هنگام اجرا با خطا مواجه می شوید که امر طبیعی و درستی است حالا جالبه بدونید که اگر این اتفاق برای توابعی که برای خود زبان PHP هستند (توابع built-in) بیفته رفتار های متفاوتی رو خواهید دید. این رفتار در این نسخه بهبود یافته.مثال زیر را در PHP 7.4 ببینید:var_dump(strlen(new stdClass));این منجر به هشدار زیر می شود:Warning: strlen() expects parameter 1 to be string, object given in /path/to/your/test.php on line 4
NULLدر PHP 8، کد بالا با خطای زیر مواجه می شود:Fatal error: Uncaught TypeError: strlen(): Argument #1 ($str) must be of type string, object given in /path/to/your/test.php:4
Stack trace:
#0 {main}
thrown in /path/to/your/test.php on line 4New Classes, Interfaces, and FunctionsWeak Map classاین کلاس Reference به یک Object را به عنوان کلید و یک مقدار را به عنوان Value قبول میکند، به شما اجازه مید یک map از Object ها و مقادیر دلخواه خود درست کنید.قبلا هم در نسخه های پیش از این می توانستیم توسط SplObjectStorage این کار رو انجام بدیم ولی این کلاس اجازه پاک کردن آن Object ها رو به Garbage Collector نمیداد اگر در این کلاس وجود داشت اما Weak Map این اجازه را می دهد.$map = new WeakMap;
$obj = new stdClass;
$map[$obj] = 42;
var_dump($map);خروجی:object(WeakMap)#1 (1) {
            [0]=&gt; array(2) { [&amp;quotkey&amp;quot]=&gt; object(stdClass)#2 (0) { }[&amp;quotvalue&amp;quot]=&gt; int(42)}
}Stringable interfaceیک interface در این نسخه اضافه شده است به نام Stringable که کلاس هایی که آن رو Implement می کنند باید تابع  ()to_string__ را پیاده سازی کنند. با وجود این interface میتوان توابع ای با ورودی یا خروجی از نوع String یا Stringable تعریف کرد:function showStuff(string|Stringable $value) {
            // A Stringable will get converted to a string here by calling
            // __toString.
            print $value;
}str_contains(), str_starts_with(), str_ends_with()در این نسخه توابع built-in به زبان PHP اضافه شده است که کار با رشته ها را برای ما آسان تر می کند، بریم با هم بررسیشون کنیم:str_contains()این تابع یک رشته را داخل رشته ی دیگری جستجو میکند و اگر پیدا شد مقدار True را باز میگرداند.پیش از این برای این کار می توانستیم از توابع strpos نیز استفاده کنیم که اگر رشته مورد نظر را پیدا نمی کرد مقدار false را برمی گرداند و اگر پیدا میکرد عدد جایی که پیدا شده بود را باز میگرداند.str_starts_with(),str_ends_with()همانطور که از اسم این دو تابع مشخص است مقدار true را برای زمانی که رشته ما، با رشته مورد نظر شروع یا تمام بشه باز میگرداند.str_starts_with (string $haystack , string $needle) : boolstr_ends_with (string $haystack , string $needle) : boolType system and error handling improvementsAbstract trait method validationدر نسخه های قبلی وقتی یک متد در Trait به صورت  abstract تعریف می شد و کلاسی که آن را پیاده سازی می کرد اگر signature متد دقیقا مثل متد abstract پیاده نمی کرد php اروری نمی داد ولی در این نسخه در رابطه با این موضوع php سختگیرانه تر عمل میکنه و ارور میده:trait T {
            abstract public function test(int $x);
}class C {
            use T;
            // Allowed, but shouldn&#039;t be due to invalid type.
            public function test(string $x) {}
}اگر در نسخه های قبلی این کد اجرا بشه اروری داده نمیشه ولی اگر در این نسخه اجرا بشه ارور زیر برگردانده میشه:Fatal error: Declaration of C::test(string $x) must be compatible with T::test(int $x) in /path//your/test.php on line 10Fatal error for incompatible method signaturesدر ارث بری اگر signature متد به درستی پیاده سازی نشه در ورژن های قبلی یک warning چاپ میکنه ولی در این ورژن با ارور مواجه میشه، برای مثال این کد در نسخه های قبل هشدار می دهد ولی در این نسخه ارور می دهد:class C1 {
            public function method(array $a) {}
}
class C2 extends C1 {
            public function method(int $a) {}
}The @ operator no longer silences fatal errorsاپراتور @ در PHP  اگر پشت دستوری قرار می گرفت و اون دستور با ارور مواجه می شد آن ارور را نادیده می گرفت و کد ادامه پیدا می کرد اما از این نسخه دیگر اینطور نیست و در صورتی که آن دستور با ارور مواجه شود کد دیگر ادامه پیدا نمی کند و ارور می دهد. برای مثال کد زیر در نسخه ها قبل ارور نمی دهد ولی در این نسخه با ارور مواجه می شود:@$a = 1 / 0;PHP 7:اروری نمی دهد و به اجرای ادامه کد می پردازد:PHP 8:Fatal error: Uncaught DivisionByZeroError: Division by zero in /home/user/scripts/code.php:7
Stack trace:
#0 {main}
thrown in /home/user/scripts/code.php on line 7Inheritance with private methodsخب همانطور که میدانید متد private را کلاس فرزند به ارث نمی برد، در ورژن ها قبلی اگر در کلاس فرزند یک متد مانند متد private کلاس والد تعریف کنیم با کمال تعجب با ارور مواجه می شویم اما در این ورژن  فقط با یک warning مواجه می شویم.class Foo {
            final private function testFoo(): void {}
}
class ChildFoo extends Foo{
            private function testFoo(): void {}
}php7:Warning: Private methods cannot be final as they are never overridden by other classes in ... on line …php 8:Fatal error: Cannot override final method Foo::testFoo() in ... on line …Mixed typeقبلا در داکیومنت های PHP این نوع داده را زیاد دیده ایم و زمانی استفاده می شود که بخواهیم نوعی تعریف کنیم که تمام نوع ها را پوشش دهد.برای مثال:function dd(mixed $var): void {
            var_dump($var);
}در کد بالا نوع ورودی تابع dd می تواند از هر نوعی باشد.Static return typeدر این نسخه امکانی فراهم شده است تا توابع را محدود کنیم که فقط مقادیر static برگردانند:class Foo {
            public static function getInstance(): static {
            return new static();
            }
}Opaque objects instead of resources for Curl, Gd, Sockets, OpenSSL, XMLWriter, and XML extensionsتوابعی مثل curl_init مقدار هایی با نوع resource باز می گرداندن که خب مشکل های خاص خودشو داشت و  Garbage Collector عملکرد خوبی با resource ها نداشت. حالا در این نسخه این توابع بجای resource ها object بر میگردانند:PHP 7:var_dump(curl_init());  //resource(5) of type (curl)PHP8:var_dump(curl_init());  //object(CurlHandle)#1 (0) {}Other syntax tweaks and improvementsTrailing Comma in Parameter Listدر ورژن های قبلی کد زیر با ارور مواجه می شود اما د این ورژن میتوان در closure function ها و ورودی هایی که   use  به تابع پاس داده می شوند بعد از آخرین ورودی کاما آورده شود:در ورژن های قبلی با ارور زیر مواجه می شود:function() use ($foo,$bar,) {}
Parse error: syntax error, unexpected &#039;)&#039;, expecting &#039;&amp;&#039; or variable (T_VARIABLE) in ... on line …Throw is now an expressionنوشتن throw در دستور های زیر باعث ارور در نسخه های قبلی میشد اما در این ورژن نوشتن آن مجاز است:$value = isset($data) ? $data : throw new \Exception(&#039;value not set&#039;);
$value ??= throw new \Exception(&#039;value not set&#039;);Allow ::class on objectsبرای چاپ کردن نام کامل کلاس ما از این User::class عبارت استفاده می کنیم این عبارت روی نام کلاس ها قابل استفاده است، در این نسخه امکان استفاده آن روی یک object نیز فراهم شده است برای مثال:User::class;
$user::class;این دو عبارت در این نسخه خروجی یکسانی دارند. https://virgool.io/@RasoulEsmaeili/%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1%D8%A7%D8%AA-php-81-wzvibvec8mn4 ممنون که تا انتهای این مقاله همراه من بودید، شادُ خندونُ سلامت باشید. (:</description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Wed, 08 Nov 2023 16:14:17 +0330</pubDate>
            </item>
                    <item>
                <title>بررسی تغییرات PHP 8.1</title>
                <link>https://virgool.io/@RasoulEsmaeili/%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1%D8%A7%D8%AA-php-81-wzvibvec8mn4</link>
                <description>حدود 20 روز پیش در تاریخ نهم جولای 2022 ورژن 8.1.8 زبان PHP منتشر شد و در این مقاله به بررسی تغییرات از نسخه 8.1 تا این نسخه می پردازم که میشه به قابلیت هایی مثل Enum ها که واقعا جاشون خیلی خالی بود یا کدنویسی Async که Fiber نام دارد و چندین قابلیت جدید دیگر اشاره کرد. ابتدا لیستی از تغییرات را تهیه کرده ام و در ادامه به توضیح و تحلیل آنها پرداخته ام.لیست تغییرات:Pure Intersection TypesEnumsThe never Return TypeNew readonly PropertiesFinal class constantsFibersNew in initializersFirst-Class Callable SyntaxExplicit Octal Numeral NotationArray Unpacking Support for String-Keyed ArraysNew fsync() and fdatasync() FunctionsNew array_is_list() FunctionPure Intersection Typesاگر یادتون باشه در PHP 8 قابلیتی اضافه شد که نوع متغیرها یا خروجی و ورودی توابع را از چند نوع به صورت همزمان مشخص کنیم که با علامت پایپ از یکدیگر جدا میشدن.class Number {
           public function __construct( private int|float $number) {
            }
}حالا تو این ورژن این قابلیت اضافه شده که بتونیم مشخص کنیم که یک متغیر باید از چند نوع باشه به صورت همزمان، لازمه که بگم برای استفاده از این قابلیت نوع داده هایی که مشخص می کنیم باید interface یا class باشه. به عبارت دیگه میتونیم اجبار کنیم که یک ورودی، خروجی یا یک متغیر حتما از یک یا چند کلاس و interface باشه.مثال:class A {
        private Traversable&amp;Countable $countableI;
        public function setIterator(Traversable&amp;Countable $countableI): void {
                         $this-&gt;countableIterator = $countableIterator;
         }
         public function getIterator(): Traversable&amp;Countable {
                        return $this-&gt;countableI;
         }
}الان کلاس A یک property داره که حتما باید از نوع Traversable و Countable به صورت همزمان باشه، همچنین توابع getter و setter آن هم باید ورودی خروجی اشان از این دو نوع به صورت همزمان باشه.یکم بیشتر توضیح  بدم که برای دوستانی که متوجه نشدن شفاف تر بشه…ببینید نوع یک object از روی کلاس آن یا کلاس پدر یا  Interface آن مشخص می شود. اگر از عملگر instanceof استفاده کنید برای اینکه تشخیص بدید که object مورد نظرتون از چه نوعی است و با هر کدوم از کلاس، کلاس والد یا Interface که پیاده سازی کرده مقایسه کنید جواب True خواهد بود.حالا تو این ورژن میشه مشخص کرد که object ما از دو نوع همزمان باشد، مثلا از نوع کلاس Model باشد و همزمان AuthInterface را پیاده سازی کرده باشد.این قابلیت بیشتر برای فریم ورک ها مفید است و مورد استفاده قرار میگیرد.Enumsقبلا که میخواستیم از enum ها در php استفاده کنیم یک کلاس تعریف می کردیم بعد enum های مورد نظرمون رو به صورت const تعریف میکردیم. کارمون رو راه می انداخت اما وقتی که قرار بود مقدار این enum ها از ورودی دریافت شود باید به صورت دستی بررسی میی کردیم که آیا مقدار درستی دارد یا نه.class Status{const DRAFT = &#x27;draft&#x27;;const PUBLISHED = &#x27;published&#x27;;const ARCHIVED = &#x27;archived&#x27;;}function acceptStatus(string $status) {...}حالا تو این ورژن enum ها به صورت کامل پشتیبانی می شوند:enum Status{case Draft;case Published;case Archived;}function acceptStatus(Status $status) {...}وقتی ورودی تابع را اجبار می کنیم که از نوع enum باشه در نتیجه حتما باید یکی از مقدار های enum را داشته باشه در غیر این صورت با ارور 500 مواجه خواهیم شد.  ( :The never Return Typeیک نوع جدید به خروجی توابع اضافه شده که اجبار میکنه اون تابع باید هیچ خروجی ضمنی و غیر ضمنی نداشته باشد و اجرای کد در آخر آن به پایان برسد و response به سمت کاربر بازگردد.خروجی غیر ضمنی یعنی مثلا نمیتونه دستوری شبیه  echo داشته باشه.برای مثال:function redirect(string $uri): never {header(&#x27;Location: &#x27; . $uri);exit();}Final class constantsوقتی که کلاسی دارای const بود و کلاس دیگری از آن ارث بری می کرد میتوانست const کلاس والد را overwrite کنه و دوباره آن را تعریف کنه، اما در این ورژن این امکان وجود دارد که const را به صورت final تعریف کنیم و جلوی overwirte شدن آن توسط کلاس فرزند را بگیریم.در ورژن های گذشته:class Foo{public const XX = &quot;foo&quot;;}class Bar extends Foo{public const XX = &quot;bar&quot;; // No error}در این ورژن:class Foo{final public const XX = &quot;foo&quot;;}class Bar extends Foo{public const XX = &quot;bar&quot;; // Fatal error}Fiberخب همونطور که میدونید ما در php همیشه به صورت sync کد زدیم و خود php این قابلیت رو نداشت که به صورت async کد بزنیم مگر اینکه از کتابخانه های موجود مثل amphp ،ReactPHP یا Guzzle برای این کار استفاده میکردیم.در این نسخه این ویژگی با نام Fiber اضافه شده.مثال:$fiber = new Fiber(function (): void {$value = Fiber::suspend(&#x27;fiber&#x27;);echo &quot;Value used to resume fiber: &quot;, $value, &quot;\n&quot;;});$value = $fiber-&gt;start();echo &quot;Value from fiber suspending: &quot;, $value, &quot;\n&quot;;$fiber-&gt;resume(&#x27;test&#x27;);در زمان اجرا روند اجرای کد به صورت کامل به تابع داخل فایبر منتقل میشه و دیگه کد اصلی امکان متوقف کردن اون رو نداره مگر از داخل خوده تابع.وقتی از داخل تابع دستور suspend اجرا میشه روند اجرا متوقف می شود و تنها با تابع resume روی object آن میتوان ادامه کد داخل Fiber را اجرا کرد. ببینیم که فریم ورک ها و کتابخانه ها چه موارد جذابی را با استفاده از fiber پیاده سازی میکنند.New in initializersاین امکان اضافه شده است که بتوان در Constructor  کلاس ها object را ساخت و به عنوان مقدار پیش فرض ورودی constructor استفاده کرد.class Service{private Logger $logger;public function __construct(Logger $logger = new NullLogger(),) {$this-&gt;logger = $logger;}}New readonly Propertiesاین امکان فراهم شده است که در کلاس ها property هایی تعریف کنیم که بعد از این که اولین بار مقدار گرفتن دیگه تغییر نکنن.class BlogData{public readonly Status $status;public function __construct(Status $status){$this-&gt;status = $status;}}قبلا اگر میخواستیم این کارو انجام بدیم باید یک کلاس تعریف می کردیم و هممون اول یک property که private باشه رو مقدار دهی می کردیم و بعد فقط برای اون getter مینویشتیم:class BlogData{
           private Status $status;public function __construct(Status $status){$this-&gt;status = $status;}public function getStatus(): Status{return $this-&gt;status;}حالا اما این امکان وجود  داره که به سادگی با کلمه readonly این کار رو انجام بدیم و حتی این property میتونه به صورت public هم باشه.از مزیت هایی readonly اینکه گارانتی خیلی خوبی به برنامه نویس میده که مقداری که در ابتدا مقدار دهی کرده به هیچ عنوان تغییر نکرده است، حتی به اشتباه توسط برنامه نویس دیگری.فقط موقع استفاده حواستون به دوتا نکته باشه که شاید از معایبش هم باشه، یکی اینکه موقع تعریف readonly حتما باید براش type تعریف کنید چون اگر تعریف نکنید به صورت پیشفرض null میشه و null هم نمیتونه readonly باشه و دومی اینکه اگر object را readonly  تعریف میکنید در جریان باشید که خود object میتونه تغییر کنه ولی اون property  که readonly تعریف کردیم همواره به حاوی همون object هست که در ابتدا مقدار دهی کردیم.First-Class Callable Syntaxقابلیت جدیدی که اضافه کرده باعث میشه ما بتوانیم آسانتر closure function بنویسیم مثلا اگر قبلا میخواستیم توابع زیر را به متغیرها تخصیص بدیم که بعدا فراخوانشون کنیم باید اینطوری می نوشتیم:$foo = [$this, &#039;foo&#039;];
$fn = Closure::fromCallable(&#039;strlen&#039;);اما حال در این ورژن میتونیم این طوری بنویسیم:$foo = $this-&gt;foo(...);
$fn = strlen(...);Explicit Octal Numeral Notationشاید خیلی کم با اعدادی به غیر از مبنایی دهدهی مثل مبانی دو یا هشت و شانزده کار کرده باشیم، در ورژن های گذشته اعداد در مبنای هشت با نشانه صفر در ابتدای اعداد مشخص می شدند که در برخی موارد گیج کننده بود:016 === 16; // false because `016` is octal for `14` and it&#039;s confusing
016 === 14; // trueحالا در این ورژن بعد از صفر باید یک حرف o هم اضافه کنیم که این گمراهی رو حل بکنه:0o16 === 16; // false — not confusing with explicit notation
0o16 === 14; // trueArray Unpacking Support for String-Keyed Arraysبا تابع array_merge که آشنا هستید، حالا operator که در ورژن 7.4 معرفی شده است میتوان دو آرایه را merge کرد:قبل از این ورژن:$arrayA = [&#039;a&#039; =&gt; 1];
$arrayB = [&#039;b&#039; =&gt; 2];
$result = array_merge([&#039;a&#039; =&gt; 0], $arrayA, $arrayB);
// [&#039;a&#039; =&gt; 1, &#039;b&#039; =&gt; 2]در این ورژن:$arrayA = [&#039;a&#039; =&gt; 1];
$arrayB = [&#039;b&#039; =&gt; 2];
$result = [&#039;a&#039; =&gt; 0, ...$arrayA, ...$arrayB];
// [&#039;a&#039; =&gt; 1, &#039;b&#039; =&gt; 2]New fsync() and fdatasync() Functionsدر این ورژن این دو تابع اضافه شده اند که البته این توابع از توابع های سیستم عامل لینوکس است که php از معدود زبان هایی بود که این توابع را پیاده سازی نکرده بود که بالاخره در این ورژن این اتفاق افتاد.تابع fsync باعث میشه ما مطمئن شویم که وقتی داده ای را داخل فایلی ذخیره می کنیم به صورت کامل روی دیسک ذخیره شود و چیزی داخل بافر های php یا خود سیستم عامل باقی نماند و هنگام فراخوانی این توابع برنامه یا process دیگری به اون فایل دسترسی نخواهد داشت:$doc = &#039;kinsta.txt&#039;;
$kin = fopen&#40;$doc, &#039;ki&#039;&#41;;
fwrite($kin, &#039;doc info&#039;);
fwrite($kin, &amp;quot\r\n&amp;quot);
fwrite($kin, &#039;more info&#039;);
fsync($kin);
fclose($kin);تابع fdatasync همانند تابع fsync عمل میکند ولی مقداری سریعتر است و زمانی بهتر است از این تابع استفاده کنیم که metadata فایل برای ما ضروری نباشید و بیشتر روی محتوای فایل تمرکز داشته باشیم.در واقع این دوتا تابع برای کسانی که برنامه های خود را بر پایه فایل می نویسند و خیلی با فایل سر و کار دارند کاربرد دارد.New array_is_list() Functionاین تابع هم در این ورژن معرفی شده است و بررسی میکند که آرایه شما از یک لیست تشکیل شده است یا خیر و مقدار true یا false را برمی گرداند. برای بیشتر شدن با این تابع به مثال های زیر دقت کنید:// true array_is_list() examples
array_is_list([]); // true
array_is_list([1, 2, 3]); // true
array_is_list([&#039;cats&#039;, 2, 3]); // true
array_is_list([&#039;cats&#039;, &#039;dogs&#039;]); // true
array_is_list([0 =&gt; &#039;cats&#039;, &#039;dogs&#039;]); // true
array_is_list([0 =&gt; &#039;cats&#039;, 1 =&gt; &#039;dogs&#039;]); // true
// false array_is_list() examples
array_is_list([1 =&gt; &#039;cats&#039;, &#039;dogs&#039;]); // as first key isn&#039;t 0
array_is_list([1 =&gt; &#039;cats&#039;, 0 =&gt; &#039;dogs&#039;]); // keys are out of order
array_is_list([0 =&gt; &#039;cats&#039;, &#039;bark&#039; =&gt; &#039;dogs&#039;]); // non-integer keys
array_is_list([0 =&gt; &#039;cats&#039;, 2 =&gt; &#039;dogs&#039;]); // gap in between keysممنون که تا انتهای این مقاله همراه من بودید، شادُ خندونُ سلامت باشید. (:</description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Wed, 03 Aug 2022 15:50:35 +0430</pubDate>
            </item>
                    <item>
                <title>هماهنگ سازی کد استایل تیم در تمام IDE های JetBrains</title>
                <link>https://virgool.io/CodeLovers/%D9%87%D9%85%D8%A7%D9%87%D9%86%DA%AF-%D8%B3%D8%A7%D8%B2%DB%8C-%DA%A9%D8%AF-%D8%A7%D8%B3%D8%AA%D8%A7%DB%8C%D9%84-%D8%AA%DB%8C%D9%85-%D8%AF%D8%B1-%D8%AA%D9%85%D8%A7%D9%85-ide-%D9%87%D8%A7%DB%8C-jetbrains-q0xxwlyyb4bm</link>
                <description>JetBrains IDEsبرنامه نویس ها معمولا بعد از به پایان رسوندن یک قسمت از کد عادت دارن که با زدن یک کلید میانبر کد استایل خودشونو مرتب کنن، این مرتب کردن هم قطعا تغییراتی توی کد ایجاد میکنه و از طرف دیگه هم که Git حواسش به همه چیز هست و همه تغییراتو ثبت میکنه در ادامه هم کد commit و سپس push و در انتها هم میرسه به Merge Request و شخصی که وظیفه Review کردن کد رو برعهده داره شروع میکنه به بازنگری کد ها، حالا تغییرات این Merge Request شامل چه چیزهایی هست؟ هم شامل کد های جدید یا تغییر در بین کد های قدیمی و همچنین شامل تغییراتی که IDE برای مرتب کردن کد استایل اعمال کرده (تغییرات کد استایلی شامل درست کردن فاصله ها، تبدیل کردن if های یک خطی به if های بلاکی و… است که البته به تنظیمات IDE برنامه نویس مربوط میشه!!) خب کسی که داره کد رو بازنگری میکنه بیشتر دنبال تغییرات مهم است و پیدا کردن این تغییرات میان تغییرات کد استایل به مرور سخت و اذیت کننده است، اما با این حال اگر فرض کنیم که تعداد افراد تیم بین 3 تا نهایت 5 نفر باشه مشکل حادی دیده نمیشه و ممکنه این تغییرات در بعضی Merge Request ها باشه و در بعضی هم نباشه چون معمولا هر کس توی تیم فقط با بعضی از فایل ها کار میکند و خب وقتی یکبار بر اساس تنظیمات IDE خودش کد استایل اون فایل تنظیم شده باشه دفعه بعد که دوباره از کلید میانبر برای مرتب کردن فایل استفاده کنه دیگر تغییری در فایل ایجاد نمیشه.حالا مشکل از کجا شروع میشه؟از اونجایی که تعداد افراد تیم رشد میکنه و کنارش پروژه هم بزرگ میشه و کلی فایل داره که کد استایلشون بر اساس تنظیمات IDE  برنامه نویسان قبلی و کنونی اش تنظیم شده، اینجاست که دیگه خوندن Merge Request ها تقریبا ناممکن میشه و تقریبا تو Merge Request همه این تغییرات کد استایل دیده میشه.حالا باید چیکار کنیم؟برای حل این موضوع راه حل های زیادی وجود داره که من از یکی از اون ها استفاده کردم که در ادامه میخوام توضیحش بدم.کاری که من تصمیم گرفتم بکنم این بود که اول سعی کردم با توجه به پیشینه پروژه و همچنین زبان پروژه که PHP بود یک استاندارد انتخاب کنم که در نهایت به PSR-12 رسیدم که از این به بعد همه ی فایل ها بر اساس اون مرتب بشن خب حالا لازمه که افراد پروژه این تنظیمات رو داشته باشند و IDE اون ها هم بر اساس این تنظیمات کد هاشونو مرتب کنه برای این کار هم یک فایل داخل پروژه ساختم که شامل همه این تنظیمات بود و از طریق git بین همه افراد تیم این فایل مشترک شد بعدش باید همه افراد تیم IDE خودشونو تنظیم می کردن که از این فایل تنظیمات رو بخونه.خب تا اینجا یک تنظیمات مشخصی رو انتخاب کردیم و از طریق git با همه افراد پروژه به اشتراک گذاشتیم و IDE های خودمون رو هم تنظیم کردیم که این فایل بخونه خب انتظار میره از این جا به بعد مشکل حل بشه و در کد های جدید کد استایل همه یکی بشه ولی در مورد کد های قدیمی پروژه که زیاد هم بودند و استایل یکسانی هم نداشتند چی؟قدم بعدی درست کردن کد های قدیمی بود. برای این کار از Branch ای که نسخه پایداری از اپلیکیشن بود یک Branch به نام FixCodeStyle ساختم و توسط IDE کد استایل تمام فایل های پروژه رو درست کردم.تعداد زیادی از فایل های پروژه (تقریبا همه فایل های پروژه) طی این Merge Request تغییر کرد و کد استایل شون درست شد. این روش کد استایل تمام فایل های پروژه رو درست کرد و تنظیمات IDE تمام افراد تیم رو همه یکسان کرد ولی تضمینی نمیده که دیگه تو Merge Request های بعدی تیم شاهد تغییرات کد استایل نباشیم چون ممکنه تنظیمات IDE یکی از افراد تیم از فایل مشترک نخونه و بر اساس تنظیمات دیگری کد هارو مرتب که و خود برنامه نویس هم متوجه این موضوع نباشه و کد های خودشو Push کنه، روش ها و ابزار های دیگه هم وجود داره که موقع Push شدن کد استایل هارو چک میکنه حالا میتونه اخطار بده یا از Push جلوگیری کنه یا اصلا خودش درست کنه، من در مرحله اول به این روش بسنده کردم و مدیریت این موضوع رو به دست برنامه نویس های تیم و Reviewer ها سپردم.خب حالا بریم که این مراحل رو در IDE های شرکت JetBrains توضیح بدم. D:تنظیم کردن کد استایل برای زبان های برنامه نویسی در IDEبرای این کار از مسیر file -&gt; setting یا با استفاده از کلید میانبر  Alt + Ctrl + S به صفحه تنظیمات بروید.سپس به صفحه ی تنظیمات کد استایل از مسیر Editor -&gt; CodeStyle -&gt; PHP یا زبان مورد نظر خودتون برید.تو این پنجر میشه تنظیمات مربوط به کد استایل رو مشخص کرد. برای تنظیم کد استایل با استاندارد های اون زبان نیازی نیست دستی این کارو انجام بدید؛ بالای این پنجره سمت راست روی Set From کلیک کنید و از لیست باز شده استاندارد مورد نظر خودتونو انتخاب کنید.
درست کردن فایل تنظیمات در پروژهابتدا اگر فایلی به نام editorconfig. در پروژه تون وجود داره پاکش کنید..editorconfig
حالا روی پوشه پروژه تون راست کلیک کنید و از گزینه New گزینه editorconfig رو انتخاب کنید.phpstorm create fileبا انتخاب این گزینه پنجره زیر نمایش داده میشه که شما میتونید زبان هایی که میخواهید تنظیماتش داخل این فایل نوشته بشه رو انتخاب کنید.فایل ایجاد شده رو توی git اضافه کنید و Push کنید که با بقیه افراد تیم بهش دسترسی داشته باشید.تنظیم کردن IDE بر اساس فایل configکافیه این گزینه رو در تنظیمات انتخاب کنید.مرتب کردن فایل های قدیمی پروژهبرای این کار روی پوشه پروژه راست کلیک کنید و گزینه  Reformat Code را انتخاب کنید.در پنجره باز شده گزینه Cleanup Code را تیک بزنید و روی run کلیک کنید.و تمام !!! D:خوشحال میشم تو کامنت ها یا به صورت ایمیل بگید که شما از چه روشی تو تیم خودتون برای این کار استفاده میکنید.ممنون از توجهتون، میتونید با لایک، کامنت و اشتراک گذاری این پست باعث دلگرمی من بشید، شادُ خندونُ سلامت باشید. (: https://virgool.io/laravel-community/%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-8-%D8%AF%D8%B1-8-%D8%AF%D9%82%DB%8C%D9%82%D9%87-uldctdxc8jnt  https://virgool.io/@Rasool.e/%DB%8C%DA%A9%D8%A8%D8%A7%D8%B1-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%87%D9%85%DB%8C%D8%B4%D9%87-position-%D9%87%D8%A7-%D8%AF%D8%B1-css-yigbex4ipvxc </description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Thu, 17 Dec 2020 13:48:20 +0330</pubDate>
            </item>
                    <item>
                <title>لاراول 8 در 10 دقیقه</title>
                <link>https://virgool.io/laravel-community/%D9%84%D8%A7%D8%B1%D8%A7%D9%88%D9%84-8-%D8%AF%D8%B1-8-%D8%AF%D9%82%DB%8C%D9%82%D9%87-uldctdxc8jnt</link>
                <description>what&#039;s new in laravel 8تیم لاراول در تاریخ هشتم سپتامبر امسال نسخه 8 این فریم ورک را منتشر کرد. این نسخه  (LTS(Long Term Support نیست و تا تاریخ April 6th, 2021 پشتیبانی عمومی و تا تاریخ September 8th, 2021 (یک سال دیگر) پشتیبانی امنیتی می شود.از تغییرات و قابلیت های جدید این نسخه میشه از تغییر پوشه مدل ها، بهبود حالت نگهداری (Improved Maintenance Mode) و تغییر Factory ها به کلاس نام برد.لیست تغییرات این نسخه:Models DirectoryModel Factory ClassesMigration SquashingJob BatchingImproved Rate LimitingImproved Maintenance ModeClosure Dispatch / Chain catchDynamic Blade ComponentsEvent Listener ImprovementsTime Testing HelpersArtisan serve ImprovementsTailwind Pagination ViewsRouting Namespace Updatesدر ادامه سعی میکنم به صورت خلاصه در مورد هر کدوم از این تغییرات بنویسم و توضیح بدم.Models Directoryاز همون اول هم که model ها در پوشه قرار نداشتن و داخل پوشه app بودن، حس بهم ریختگی و شلوغی بعد از بزرگ شدن پروژه همه رو کلافه می کرد. حالا بالاخره در این نسخه با توجه به درخواست های زیاد، پوشه ی model در داخل پوشه app برای مدل ها در نظر گرفته شده است و از این نسخه به بعد باید برای پیدا کردن مدل ها به app/model مراجعه کنیم.Model Factory Classesدر واقع factory ها در تست نویسی کاربرد دارند، آنجایی که نیاز به اطلاعاتی در دیتابیس داشته باشیم تا بتونیم شرایط مناسب برای اجرای تست رو فراهم کنیم.پیش از این factory ها به صورت کلاس نبودند و باید با متغیری که نمونه ای از \Illuminate\Database\Eloquent\Factory بود کار میکردیم و factory خودمون رو تعریف می کردیم.حالا در این نسخه تبدیل به کلاسی جداگانه شده اند، در واقع باید برای تعریف factory، یک کلاس جدید ایجاد کنیم که البته از Command های artisan برای این کار استفاده میکنیم تا این کلاس رو برای ما ایجاد کند ولی به هر ترتیب قالب نوشتاری factory در نسخه هشتم لاراول به صورت کلاس تغییر پیدا کرده است و با این تغییر قابلیت های جدیدی نیز به factory اضافه شده است.بر اساس داکیومنت لاراول روابط بین مدل ها نیز در factory ها لحاظ شده است و بدین ترتیب میشه  factory مدل های دیگه که با مدل مد نظر ما ارتباط دارند رو نیز صدا کرد تا اطلاعات مورد نیاز ما برای اون مدل هم در دیتابیس نوشته بشه.برای مثال فرض کنید که مدل user ما با مدل post ارتباط دارد و می خواهیم تعدادی user به همراه post هاشون در دیتابیس ایجاد کنیم: (با فرض اینکه factory های لازم رو از قبل نوشته باشیم.)$users = User::factory()
       -&gt;hasPosts(3, [&#039;published&#039; =&gt; false])
        -&gt;create();به همین راحتی !!!همچنین این امکان وجود دره که ما متد هایی به کلاس Factory خودمون اضافه کنیم و هنگام استفاده از factory ها اون هارو صدا کنیم.Migration Squashingطی زمانی که پروژه بزرگ و بزرگتر میشه ما هم به مرور migration های زیادی می نویسیم که تعدادشون خیلی زیاد میشه در برخی موارد به صد ها migration هم میرسه و این موضوع باعث شلوغ شدن پوشه migration ها میشه و مشکل دیگه که به وجود میاد اینکه برای مثال فرض کنید که در ماه سوم تصمیم میگیریم که ستونی به پروژه اضافه کنیم و migration مورد نیاز رو بنویسیم و در ماه پنجم تصمیم به تغییر یا حذف اون ستون میگیریم و migration مورد نیاز اون رو هم می نویسیم حالا فرض کنید که عضو جدیدی به تیمتون اضافه میشه و بعد از pull کردن پروژه migration هارو اجرا میکنه خب چی میشه؟ با توجه به migration هایی که در مثال فرض کردیم به ترتیب migration ماه سوم و بعد ماه پنجم اجرا میشه و در واقع یک عملی انجام می شود و در ادامه یا تغییر میکند یا اون عمل به طور کامل پاک میشود در صورتی که ما فقط به آخرین شکل دیتابیس نیاز داریم و طی این مراحل داریم یک عمل اضافه ای رو انجام میدیم. برای درک عمق بد بودن ماجرا تصور کنید که صد ها migration داریم و تعداد این عمل های اضافی بسیار زیاد است و همچنین فرض کنید که برای هر بار اجرای تست های پروژه که دیتابیس خود را در حافظه نگه می دارند این اتفاق می افتد.شاید فکر کنید مشکل کار از migration ها باشه ولی در حقیقت این ذات اون هاست که دقیقا تغییرات جز به جز دیتابیس پروژه رو ذخیره کنند و این یکی از مزیت های اونهاست.برای بهبود ماجرا آقای Taylor Otwell عزیز زحمت کشیدن و migration squashing رو طراحی کردند. کاری که این ابزار انجام میده اینکه ما میتونیم کامند php artisan schema:dump را اجرا کنیم تا یک فایل در پوشه database/schema ساخته بشه و حاوی کد های  sql ای باشه که ساختار فعلی دیتابیس پروژه را ایجاد میکنه، حالا هر بار قبل از اجرا شدن migration ها، این فایل اجرا میشه و بعد از اون تنها migration هایی اجرا میشن که در این فایل لحاظ نشده باشن.Job Batchingاین قابلیت جدید به برنامه نویس اجازه میده تعداد زیادی از job هارو اجرا کنه و بعد از اون با توجه به نتیجه تابع call back مناسب با اون نتیجه رو بنویسه، برای اینکه بهتر متوجه بشین اول یک مثال میزنم:$batch = Bus::batch([
         new ProcessPodcast(Podcast::find(1)),
         new ProcessPodcast(Podcast::find(2)),
         new ProcessPodcast(Podcast::find(3)),
         new ProcessPodcast(Podcast::find(4)),
         new ProcessPodcast(Podcast::find(5)),
      ])-&gt;then(function (Batch $batch) {
                  // All jobs completed successfully...
      })-&gt;catch(function (Batch $batch, Throwable $e) {
                  // First batch job failure detected...
      })-&gt;finally(function (Batch $batch) {
                  // The batch has finished executing...
      })-&gt;dispatch();خب در مثال بالا دسته ای از job ها برای اجرا نوشته شده و بعد از اون هم توابعی برای حالت های مختلف، در ادامه این توابع رو بررسی میکنیم.تابع then: میتونیم بعد اجرا شدن موفق job ها دستوراتی رو اجرا کنیم.تابع catch: میتونیم بعد از رخ دادن خطا دستوراتی رو اجرا کنیم.تابع finally: میتونیم فارغ از هر نتیجه ای دستوراتی را اجرا کنیم.Improved Rate Limitingاین امکان در لاراول وجود داشت که route ها رو محدود کنیم تا در مدت زمان مشخصی یک نفر فقط بتواند تعداد مشخصی request ارسال کند، حالا در این نسخه این قابلیت هم بهبود یافته هم ارتقاء پیدا کرده است.با استفاده از facade به نام RateLimiter و تابع for می تونیم این محدودیت رو تعریف کنیم. تابع for دوتا ورودی داره که اولیش نام و دومی یک تابع callback است و از اونجایی که در این تابع callback دسترسی به request داریم میتونیم با توجه به اطلاعات اون درخواست، مثلا وضعیت authenticate ارسال کننده درخواست و غیره شرایط محدودیت رو به صورت داینامیک و پویا تعیین کنیم.برای مثال میخواهیم کاربران VIP هیچ محدودیتی نداشته باشند و بقیه کاربران فقط بتونن تو هر دقیقه 100 درخواست ارسال کنند:RateLimiter::for(&#039;uploads&#039;, function (Request $request) {
               return $request-&gt;user()-&gt;vipCustomer()
               ? Limit::none()
               : Limit::perMinute(100)-&gt;by($request-&gt;ip());
});حالا برای استفاده از Rate Limit هایی که مینویسیم، کافیه اسم اون هارو به throttle در هنگام تعریف یک route نسبت دهیم:Route::middleware([&#039;throttle:uploads&#039;])-&gt;group(function () {
        Route::post(&#039;/audio&#039;, function () {
                       //
        });
});Improved Maintenance Modeدر نسخه قبلی لاراول وقتی که کامند php artisan down را اجرا می کردیم این امکان وجود داشت که یک لیست از IP ها رو مشخص کنیم تا در تمام مدتی که کل اپلیکیشن پایین است و از دسترس تمام کاربران خارجه این IP ها به تمام اپلیکیشن دسترسی داشته باشند.حالا در این نسخه این قابلیت حذف شده است و جای خودش رو به Secret token داده است:php artisan down --secret=&amp;quot1630542a-246b-4b66-afa1-dd72a4c43515&amp;quotهنگامی که اپلیکیشن پایین است به route مخفی زیر یک Request ارسال می کنیم و یک cookie برای ما set میشه و بعد از اون میتونیم به کل اپلیکیشن دسترسی داشته باشیم.https://example.com/1630542a-246b-4b66-afa1-dd72a4c43515Pre-Rendering The Maintenance Mode Viewقابلیت دیگه ای هست که به این بخش اضافه شده است و باعث میشه قبل از پایین رفتن اپلیکیشن View مورد نیاز Maintenance Mode رندر بشه و آماده باشه. این قابلیت به این دلیل اضافه شده، چون قبلا وقتی در حال update کردن قسمت هایی از پروژه بودیم لاراول برای render کرد view مورد نیاز ممکن بود با مشکل مواجه بشه و کاربران ارور دریافت کنند حالا با این قابلیت view از قبل آماده است و این امکان به حداقل میرسه.Closure Dispatch / Chain catchدر این نسخه میتونیم برای job هایی که به صورت closuer هستند یک تابع catch بنویسیم تا اگر بعد از تمام تلاش های مجدد باز هم انجام نشد این تابع اجرا بشه:dispatch(function () use ($podcast) {
                $podcast-&gt;publish();
      })-&gt;catch(function (Throwable $e) {
                  // This job has failed...
});Dynamic Blade Componentsدر برخی مواقع هست که تا زمان اجرای کد نرسه، نمیدونیم کدوم component باید render بشه، در این مواقع میشه از این قابلیت جدید استفاده کرد، کافیه اسم component مورد نظر که موقع اجرای کد مشخص شده است را به dynamic-component نسبت دهیم.&lt;x-dynamic-component :component=&amp;quot$componentName&amp;quot class=&amp;quotmt-4&amp;quot /&gt;Event Listener Improvementsبرای این بخش امیدوارم با closure event listener ها آشنا باشید چون توضیحش از حوصله این مقاله خارجه، شاید بعدا یک مطلب جداگانه در موردشون نوشتم و توضیحشون دادم.به هر حال در این نسخه closure event listener ها بهبود یافته اند و هنگام تعریفشون فقط کافیه یک تابع closure بنویسیم و نوع event ورودی رو مشخص کنیم:Event::listen(function (PodcastProcessed $event) {
                //
});برای queue کردن هم کافیه از تابع Illuminate\Events\queueable استفاده کنیم:Event::listen(queueable(function (PodcastProcessed $event) {
                //
}));و در آخر هم باید بگم که مانند بقیه job ها متد های onConnection, onQueue , delay و catch  اضافه شده اند:Event::listen(queueable(function (PodcastProcessed $event) {
               //
})-&gt;onConnection(&#039;redis&#039;)-&gt;onQueue(&#039;podcasts&#039;)-&gt;delay(now()-&gt;addSeconds(10)));
Event::listen(queueable(function (PodcastProcessed $event) {
                //
})-&gt;catch(function (PodcastProcessed $event, Throwable $e) {
               // The queued listener failed...
}));Time Testing Helpersدر تست نویسی خیلی از اوقات نیازه که ما بتونیم زمان فعلی رو تغییر بدیم و به اصطلاح در زمان سفر کنیم تا بتونیم سیستم رو در شرایط مورد نظر قرار بدیم و تست کنیم حالا در این نسخه لاراول این امکان رو برای ما به سادگی فراهم کرده:public function testTimeCanBeManipulated(){
        // Travel into the future...
        $this-&gt;travel(5)-&gt;milliseconds();
        $this-&gt;travel(5)-&gt;seconds();
        $this-&gt;travel(5)-&gt;minutes();
        $this-&gt;travel(5)-&gt;hours();
        $this-&gt;travel(5)-&gt;days();
        $this-&gt;travel(5)-&gt;weeks();
        $this-&gt;travel(5)-&gt;years();
        
        // Travel into the past...
        $this-&gt;travel(-5)-&gt;hours();
        
        // Travel to an explicit time...
        $this-&gt;travelTo(now()-&gt;subHours(6));
        
        // Return back to the present time...
        $this-&gt;travelBack();
}Artisan serve Improvementsبا دستور php artisan serve که هممون آشنایی داریم، این دستور هم در این نسخه بهبود یافته و دیگر نیاز نیست وقتی متغیری رو در env. تغییر میدیم به صورت دستی دستور serve رو دوباره راه اندازی کنیم و به صورت خودکار لاراول متوجه تغییرات این فایل میشه.Tailwind Pagination Viewsلاراول تصمیم گرفته به صورت پیشفرض از فریم ورک Tailwind برای pagination در view ها استفاده کنه، Tailwind یکی از بهترین فریم ورک های css هست که واقعا استایل دادن رو نسبتا آسون تر میکنه. با این حال هنوز هم Bootstrap نسخه 3 و 4 نیز در دسترس هست.Routing Namespace Updatesدر نسخه های قبلی وقتی میخواستیم یک route تعریف کنیم به این شکل تعریف میکردیم:Route::get(&#039;/user&#039;, &#039;UserController@index&#039;);و فقط اسم controller رو مینوشتیم وخود لاراول namespace لازم برای رسیدن به اون controller رو به ابتدای نام controller اضافه می کرد اما حالا تو این نسخه باید آدرس کامل controller رو ذکر کنیم:Route::get(&#039;/user&#039;, [UserController::class, &#039;index&#039;]);و اگر میخواهیم مثل قبل فقط اسم controller رو بنویسیم باید بریم داخل RouteServiceProvider و property $namespace رو مقداردهی کنیم.ممنون ازتوجه تون، یک خسته نباشید به شما میگم ویکی هم به خودم برای این مطلب نسبتا طولانی. شادُ خندونُ سلامت باشید. (: https://virgool.io/@Rasool.e/%DB%8C%DA%A9%D8%A8%D8%A7%D8%B1-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%87%D9%85%DB%8C%D8%B4%D9%87-position-%D9%87%D8%A7-%D8%AF%D8%B1-css-yigbex4ipvxc </description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Sat, 31 Oct 2020 12:51:26 +0330</pubDate>
            </item>
                    <item>
                <title>ES5 vs ES6 - بخش سوم</title>
                <link>https://virgool.io/@RasoulEsmaeili/es5-vs-es6-%D8%A8%D8%AE%D8%B4-%D8%B3%D9%88%D9%85-gznyvdpwwnnl</link>
                <description>سلام دوستان خوش اومدین به بخش سوم،  تا الان دو بخش از این سری رو پشت سر گذاشتیم که امیدوارم مطالعه کرده باشید. در بخش اول و دوم هشت عنوان اول لیست بررسی شد در این بخش نیز به ادامه عناوین لیست خواهم پرداخت.لیست تغییرات این نسخه :Block-Scoped Variables and Constants (let, const)Arrow FunctionsDefault Parameter ValuesSpread OperatorString InterpolationRaw String AccessPromisesBinary &amp; Octal LiteralRegular Expression Sticky MatchingManipulating objectsValue Export/ImportClassesSymbol TypeIterator &amp; For-Of OperatorGeneratorsMap/Set &amp; WeakMap/WeakSetNew Built-In MethodsRegular Expression Sticky Matchingخب، Regular Expression یا عبارت های منظم مجموعه ای از کاراکتر هاست که ما توسط آن ها یک الگو برای رشته ها تعریف می کنیم. این الگو ها به ما کمک می کنند کارهایی زیادی با رشته ها انجام بدیم مثل اعتبار سنجی رشته های ورودی و غیره .تعریف یک عبارت منظم:new RegExp(/ab+c/, &#039;i&#039;) // literal notation
new RegExp(&#039;ab+c&#039;, &#039;i&#039;) // constructor
var patt = /ab+c/;در جاوا اسکریپت از چند راه میشه از عبارت های منظم استفاده کرد://Using String search()
let res = &amp;quotrasool&amp;quot.search(/ol/); // output: 4
//Use String replace()
&amp;quotrasool esmaili!&amp;quot.replace(/rasool/, &amp;quotamin&amp;quot) // output: amin esmaili
//Using test()
let patt = /^r/ ; // any string start with r
patt.test(&amp;quotrasool esmaili&amp;quot); // output: true
//Using exec&#40;&#41;
/go+gle/.exec&#40;&amp;quotwww.google.com&amp;quot&#41; // output: googleچند Flag وجود داره که باعث تغییر رفتار عبارت های منظم میشه. Flag ها دقیقا بعد از عبارت منظم قرار میگیرند مثلا:/go+gle/i.exec&#40;&amp;quotwww.GooGlE.com&amp;quot&#41; // output: GooGlEکاراکتر i که دقیقا بعد از تمام شدن عبارت منظم اومده باعث میشه نسبت به بزرگ و کوچک بودن حروف حساس نباشد.حالا در ES6 چند Flag اضافه شده است :y Flag (sticky)با استفاده از این Flag می تونیم جستجو را دقیقا ازیک قسمت خاص از رشته شروع کنیم، به این صورت که از نقطه ای که ما تعیین میکنیم یک به یک کاراکتر ها را با عبارت منظم  بررسی می کند و اگر به رشته دلخواه نرسد جستجو را متوقف میکند و مقدار null را بر میگرداند در حالی که ممکن است رشته حاوی مقدار مدنظر عبارت منظم باشه اما در نقطه ای که ما تعیین کردیم پیدا نشده باشه:let text = &amp;quothello1 hello2 hello3&amp;quot,
pattern = /hello\d\s?/,
// ----- start from position 0 and looking for hellox so find hello1
pattern.lastIndex = 0;
pattern.exec&#40;text&#41;; // hello1
// ----- start from position 2 and looking for hellox so find nothing
pattern.lastIndex = 2;
pattern.exec&#40;text&#41;; // null
// ----- start from position 7 and looking for hellox so find hello2
pattern.lastIndex = 7;
pattern.exec&#40;text&#41;; // hello2Manipulating objectsدستکاری، مقداردهی و کار با Object ها در ES6 خیلی راحت تر شده برای مثال استفاده از اپراتور Spread که در بخش اول بررسی کردم برای ادغام کردن دو Object و غیره، در ادامه نمونه هایی از این تغییرات را اوردم:ادغام کردن :ES5:var obj1 = { a: 1, b: 2 }
var obj2 = { a: 2, c: 3, d: 4}
var obj3 = Object.assign(obj1, obj2)ES6:const obj1 = { a: 1, b: 2 }
const obj2 = { a: 2, c: 3, d: 4}
const obj3 = {...obj1, ...obj2}تبدیل یا مقدار گرفتن از ObjectES5:var obj1 = { a: 1, b: 2, c: 3, d: 4 }
var a = obj1.a
var b = obj1.b
var c = obj1.c
var d = obj1.dES6:const obj1 = { a: 1, b: 2, c: 3, d: 4 }
const { a,  b,  c,  d } = obj1ساخت ObjectES5:var a = 1 , b = 2 , c = 3 , d = 4
var obj1 = { a: a, b: b, c: c, d: d }ES6:var a = 1 , b = 2 , c = 3 , d = 4
var obj1 = { a, b, c, d }Value Export/Importدر این نسخه به طور کلی syntax این کار (Export/Import) عوض شده و همچنین این امکان فراهم شده که چندین مقدار را جداگانه export و import کنیم.ES5:var someModule = { code: 200, message: function(){ console.log(&#039;This is ES5&#039;) }}
module.exports = myModule;ES6:const someModule = {code: 200, message: () =&gt; { console.log(&#039;This is ES6&#039;) }}
export myModule;
//multiple value
export const x = 1;
export const y = 2;
export const z = &#039;String&#039;
import {x, y, z} from &#039;./someModule ;می خواستم در مورد Class ها هم در این بخش براتون بنویسم اما فکر می کنم تا اینجا هم خیلی طولانی شده باشه، انشالله اگر عمری باقی باشه در بخش بعدی براتون می نویسم. ممنون ازتوجه تون. شادُ خندونُ سلامت باشید. (:</description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Thu, 17 Sep 2020 13:17:16 +0430</pubDate>
            </item>
                    <item>
                <title>یکبار برای همیشه POSITION ها در CSS</title>
                <link>https://virgool.io/@RasoulEsmaeili/%DB%8C%DA%A9%D8%A8%D8%A7%D8%B1-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%87%D9%85%DB%8C%D8%B4%D9%87-position-%D9%87%D8%A7-%D8%AF%D8%B1-css-yigbex4ipvxc</link>
                <description>این مبحث یکی از مباحثی است که حتی اگر شما همین الان هم بخونید ممکنه پنج دقیقه بعد یادتون بره در حالی که بارها  و  بارها از اون استفاده کردین یا خیلی از مصاحبه های Front-End با این سوال شروع میشه و ممکنه که اون لحظه جملات مرتبی دم دستتون نباشه که به راحتی جواب بدین. امروز در ادامه قصد دارم به این مسئله خاتمه بدم، به همین دلیل سعی می کنم خیلی خلاصه توضیح بدم و هر کدوم از مقدارها رو نشانه گذاری کنم که راحت تر به ذهن سپرده بشه.به این property مقدار های زیر رو میشه اختصاص داد :staticfixedrelativeabsolutestickystaticمقدار پیش فرض static هست و با هیچ یک از (top, bottom, left, ,right) جابجا نمی شود و طبق روال معمولی که کل صفحه داره قرار میگیره .هرچیزی یک پیش فرض داره، پیش فرض position هم static هست. static یعنی ایستا، یعنی تغییر نمیکنه که خب منطقی هم هست وقتی position نداره پس نباید با هیچ یک از (top, bottom, left, ,right) تغییر کنه و باید سرجایی که تعریف شده قرار بگیره.fixedتنظیم کردن این مقدار باعث میشه المنت بدون توجه به اسکرول شدن صفحه جای خود رو حفظ کنه. مثلا زمانی که بخواهیم بگیم این المنت همیشه گوشه سمت راست صفحه باشه و تغییر نکنه حتی اگر صفحه رو اسکرول کنیم .مثال بدیهی fixed هم دکمه های هست که همیشه گوشه پایین صفحه ظاهر میشه و شما رو به بالای صفحه منتقل میکنه .محل قرار گیری المنتی که fixed هست رو میشه با استفاده از (top, bottom, left, ,right) نسبت به کل صفحه (نه المنت های دیگر) مشخص کرد.stickyبرای واضح شدن sticky با مثال شروع میکنم:این منو هایی که جایی ثابتی دارند ولی به محض اینکه شما صفحه رو به سمت پایین اسکرول می کنید می چسبند به بالای صفحه و دوباره وقتی به سمت بالا بر میگردید جای خودشون قرار میگیرند، مثال خوبی هست که به ذهن بسپارید.درواقع شما position المنتی رو برابر sticky قرار میدید و براش جایی دیگری نسبت به کل صفحه با (top, bottom, left, ,right)  مشخص می کنید ، حالا وقتی ViewPort (کل فضایی که دیده میشه) به اون المنت میرسه سریع میچسبه به جایی که شما براش تعریف کردید.تقریبا همه ما با سه مقدار بالا مشکلی نداریم، حالا بریم سروقت دو مقدار relative و absolute.relativeمقداری دهی position با مقدار relative باعث میشه بتونیم با استفاده از (top, bottom, left, ,right) جای المنت رو تغییر بدیم.سوال مهم اینجاست که جای المنت نسبت به چه چیزی تعیین میشه؟ به عبارت دیگه یعنی وقتی شما position رو relative می کنید و مثلا right را با 10px مقدار دهی می کنید المنت 10px از راست نسبتبب به چه چیزی فاصله می گیرد؟مقدار relative باعث میشه المنت نسبت به جایی که تعریف شده است جابجا شود.absoluteاین مقدار هم مانند relative باعث میشه که بتوانیم با استفاده از (top, bottom, left, ,right) جای المنت رو تغییر بدیم، اما تفاوت اینجاست که absolute بر خلاف relative دیگر نسبت به جایی که تعریف شده است تغییر نمیکند، بلکه نسبت به اولین پدری که مقدار position آن برابر هر چیزی به غیر از static باشد تغییر می کند.برای مثال :&lt;div style=”position:relative” name=”1”&gt;
         &lt;div name=”2”&gt;
                  &lt;p style=”position:absolute; right:10px”&gt;some text&lt;/p&gt;
         &lt;/div&gt;
&lt;/div&gt;اتفاقی که اینجا افتاده اینه که تگ p نسبت به div یک جابجا میشود نه div دو.نکته : اگر تگی که absolute هست هیچ پدری نداشته باشد که position گرفته باشد، نسبت به تگ body جابجا می شود.ممنون از توجه تون امیدوارم مفید بوده باشه، شادو خندونو سلامت باشید. (:</description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Wed, 06 May 2020 10:25:50 +0430</pubDate>
            </item>
                    <item>
                <title>ES5 vs ES6 - بخش دوم</title>
                <link>https://virgool.io/@RasoulEsmaeili/es5-vs-es6-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-lyqbfgmf5uaz</link>
                <description>سلام دوستان خوش اومدین به بخش دوم، در بخش اول به بررسی چهار عنوان اول از لیست زیر پرداختیم که اگر مطالعه نکردین میتونین از اینجا مطالعه کنید.لیست تغییرات این نسخه :Block-Scoped Variables and Constants (let, const)Arrow FunctionsDefault Parameter ValuesSpread OperatorString InterpolationRaw String AccessPromisesBinary &amp; Octal LiteralRegular Expression Sticky MatchingManipulating objectsValue Export/ImportClassesSymbol TypeIterator &amp; For-Of OperatorGeneratorsMap/Set &amp; WeakMap/WeakSetNew Built-In MethodsString Interpolationخیلی از مواقع میخواهیم متغیری را میان یک رشته قرار دهیم مخصوصا وقتی با HTML کار میکنیم.خب کاری که در ES5 می کردیم اینطوری بود :var message = &amp;quotmy name is :  &amp;quot + person.name + &amp;quot\n&amp;quot ;حالا در ES6 این کارو میتونیم خیلی راحت تر انجام بدیم :var message = `my name is:  ${person.name} \n`;با کمک &#x60;&#x60; این دو عزیز که خیلی کم کسی ازشون استفاده میکنه و کمتر کسی اسمشو میدونه میشه در میان رشته با استفاده از {}$ متغیر را قرار داد.Raw String Accessرشته ها از یک سری کاراکتر تشکیل شده اند که پشت سر هم آمده اند، خب حالا در ES6 این امکان وجود داره که بشه به کاراکترهای رشته ها مثل خانه های آرایه دسترسی داشت.const city = ”tehran”;
console.log(city[2]); // h
console.log(city[3]); // r
console.log(“virgool”[4]); // oPromises vs Callbacksجاوا اسکریپت یک زبان async هست و خیلی از مواقع نیاز داریم که از callback ها استفاده کنیم. وقتی نیاز باشه این callback ها تو دل هم صدا زده بشن در انتها یک کد ناخوانا و پیچیده خواهیم داشت. خوشبختانه در این مورد promises ها در ES6 به ما کمک می کنند.یک promise یه صورت زیر تعریف میشه :const somePromise = new Promise((resolve, reject) =&gt; {
        if (false) {
                resolve([20, 30, 40]);
        } else {
                  reject(&amp;quotsome error occur&amp;quot);
        }
});ورودی های resolve , reject هستند که در صورت موفق بودن باید resolve و در صورتی که موفقیت آمیز نباشد باید reject را با دیتایی که میخواهیم مقدار دهی کنیم .استفاده از promise :somePromise.then( resolveResult =&gt; {
        console.log(resolveResult);
}).catch(rejectResult =&gt; {
        console.log(rejectResult);
});برای استفاده باید دو تابع then , catch را پیاده سازی کنیم، در صورتی که promise با resolve به پایان برسد تابع then  و اگر با reject به پایان برسد تابع catch به طور خودکار فراخوانی می شود و دیتایی که promise برگردانده است در اختیار این دو تابع هنگام فراخوانی قرار می گیرد.Binary &amp; Octal Literalبرای نوشتن اعداد مبنای 8 و 2 در ES5 باید به صورت زیر عمل میکردیم .var value = parseInt(&amp;quot111110111&amp;quot, 2); //503
var value = parseInt(&amp;quot767&amp;quot, 8); //503;حالا در ES6 میتونیم با پیشوند این کارو خیلی راحت تر انجام بدیم و لازم به تبدیل نیست :let value = 0b111110111; // 503
let value = 0o767 ; //503به پایان بخش دوم رسیدیم امیدوارم مفید بوده باشه.</description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Fri, 10 Apr 2020 12:32:19 +0430</pubDate>
            </item>
                    <item>
                <title>ES5 vs ES6 - بخش اول</title>
                <link>https://virgool.io/@RasoulEsmaeili/es5-vs-es6-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-l2z1oigqis1j</link>
                <description>زبان جاوااسکریپت مثل بقیه زبان ها نسخه های مختلفی دارد که ES6 و ES5 از نسخه های این زبان هستند. نسخه ES6 در سال 2015 منتشر شد و یکی از نسخه هایی است که بیشترین تغییرات را ایجاد کرده است.لیست تغییرات این نسخه : Block-Scoped Variables and Constants (let, const)Arrow FunctionsDefault Parameter ValuesSpread OperatorString InterpolationRaw String AccessPromisesBinary &amp; Octal LiteralRegular Expression Sticky MatchingManipulating objectsValue Export/ImportClassesSymbol TypeIterator &amp; For-Of OperatorGeneratorsMap/Set &amp; WeakMap/WeakSetNew Built-In Methodsدر ادامه به توضیح مختصر و تفاوت آن با نسخه قبلی می پردازم.Block-Scoped Variables and  Constants (let, const) دو کلید واژه ی let و const در ES6 اضافه شده که  Block-scope هستند .اسکوپ ها در واقع حوزه دید متغیر ها هستند به عبارت دیگر مشخص می کنند که متغیری که تعریف می کنیم در چه قسمتی از کد دسترس پذیر هست.در نتیجه Block-Scope  به دو اسکوپ  Global و Function که در ES5 وجود داشت اضافه شد.بلاک اسکوپ یعنی فقط متغیر داخل همون بلاک از کد در دسترس است، بلاک کد با  این &quot;{}&quot; پرانتز ها مشخص می شود و می تواند هر بلاکی باشد از بلاک if گرفته تا تابع و ... حتی بلاکی که خودمون ایجاد کرده باشیم.در ES5{ 
  var x = 2; 
 }در ادامه کد، x در خارج از بلاک نیز در دسترس است .در ES6 :{ 
  let x = 2;
  const y = 10 ;
}در ادامه کد، x و y در خارج از بلاک در دسترس نیستند .const :با کلمه کلیدی const می توان ثابت ها را تعریف کرد ، باید در ابتدا مقداردهی شوند و در ادامه کد نمی توان مقدار اون هارو عوض کرد .const PI = 3.141592653589793;let :در  ES5 برای تعریف متغیر از کلید واژه var استفاده میکردیم ، حالا let نیز اضافه شده که این امکان رو فراهم میکنه تا متغیرهای بلاک اسکوپ داشته باشیم .let name = &#039;rasool esmaili&#039;;Arrow Functions : نوع جدیدی از نوشتن توابع که syntax نوشتن توابع را کوتاه تر می کند : ES5 :helloWord = function() {
         return &amp;quotHello World!&amp;quot
}ES6 :hello = () =&gt; {
         return &amp;quotHello World!&amp;quot
}

//Shorter
helloWord= () =&gt; &amp;quotHello World!&amp;quot
//you can remove parentheses if have only one parameter
helloWord = value =&gt; &amp;quotHello &amp;quot + value;نکته : مراقب استفاده از this باشید ، وقتی از تابع معمولی استفاده می کنید this به آبجکتی که این تابع رو فراخوانی کرده اشاره داره اما Arrow Function ها به آبجکتی که تابع در آنجا تعریف شده است اشاره دارد.Default Parameter Values در این نسخه این امکان وجود دارد که برای پارامتر های ورودی تابع مقدار پیش فرض تعیین کنیم . function getName(name = &#039;rasool&#039;) {
         return &amp;quotname is : &amp;quot + name;
}
getName(); // return : name is rasool
getName(&#039;amin&#039;); // return : name is aminSpread Operatorاین اپراتور که به شکل سه نقطه &quot;...&quot;هست، بسته به جایی که استفاده می شود کاربرد های مختلفی دارد.در تعریف تابع: اگر هنگام تعریف تابع پشت پارامتر ورودی بیاید، می توان تابع را با هر تعداد پارامتر فراخوانی کرد و همه پارامترها را در آرایه ای در بدنه تابع دریافت کرد :function sum(...numbers) {
         let sum = 0;
         for (let number of numbers) sum += number;
         return sum;
}
alert&#40; sum(1&#41; );
alert&#40; sum(1, 2&#41; );
alert&#40; sum(1, 2, 3&#41; );در هنگام فراخوانی توابع : می توان با استفاده از این اپراتور ورودی های توابع را با آرایه ای مقدار دهی کرد :function myFunction(a, b, c, d, e) { 
            //parameters get : a=100, b=200, c=300, d=400, e=500 
} 
const args = [200, 300];
myFunction(100, ...args, 400, ...[500]);درArray ها :const city1= [&#039;tehran’, &#039;karaj&#039;];
const cities = [&#039;esfahan&#039;, ...city1, &#039;shiraz’, &#039;yazd&#039;];
//  [&#039;esfahan&#039;, &#039;tehran’, &#039;karaj&#039;, &#039;shiraz’, &#039;yazd&#039;]

//can merge 2 array
const city1= [&#039;tehran’, &#039;karaj&#039;];
const citiy2 = [&#039;esfahan&#039;, &#039;shiraz’, &#039;yazd&#039;];
const allCities = [...city1, ...city2];
//  [&#039;tehran’, &#039;karaj&#039;, &#039;esfahan&#039;, &#039;shiraz’, &#039;yazd&#039;]در Object ها :// initialize new object
class person {
         constructor(name, family, age){
                  this.name = name;
                  this.family = family;
                  this.age = age;
         }
}
rasool = new person( ...[&#039;rasool&#039;, &#039;esmaili&#039;, 15] );

//copy and merge
const person1 = { name: ‘rasool&#039;, family: ‘esmaili’ };
const person2 = { name: ‘amin’, age: 15 };

//can clone object
const copyPerson1 = { ...person1 };
// copyPerson1 { name: ‘rasool&#039;,  family: ‘esmaili’ }

const mergedPerson = { ...person1, ...person2 };
//mergedPerson { name: ‘rasool&#039;, family: ‘esmaili’ , age: 15 }خب به پایان بخش اول رسیدیم، امیدوارم تا اینجا مفید بوده باشه. ادامه تغییرات این نسخه رو در بخش های بعدی بررسی خواهیم کرد .</description>
                <category>رسول اسماعیلی</category>
                <author>رسول اسماعیلی</author>
                <pubDate>Thu, 02 Apr 2020 17:59:53 +0430</pubDate>
            </item>
            </channel>
</rss>