سرمایه گذاری متفاوت در سال نو 🍎🌱 ۳۵٪ تخفیف نوروزی ➕ حضور رایگان در مسترمایند نخبگان صنعت نرم‌افزار 💻✅
۰ ثانیه
۰ دقیقه
۰ ساعت
۲۱ محمدجوکار
ست کردن چند پراپرتی به طور همزمان
جامعه پی اچ پی ایجاد شده در ۰۷ بهمن ۱۴۰۱

سلام واحترام

من اگر بخوام اینجا چندین پراپرتی رو با همدیگه ست کنم توسط سترشون، باید به چه نحو عمل کنم؟؟؟

البته چیزی که من نوشتم امکان‌پذیر نیست انگار ولی آیا چیزی شبیه به این هست؟

1284-Screenshot (634).png

سلام،

برای پیاده سازی method chaining انتهای هر متد ست return $this رو بنویسید.

محسن موحد ۰۷ بهمن ۱۴۰۱، ۰۷:۵۱

عه درست شد.

الان چه اتفاقی افتاد؟؟؟

متوجه ارتباطشون نمیشم که چطوری این موضوع، روی اون تاثیر داشت. ممنون میشم اگر یه توضیح کوچیک بدید

3814-Screenshot (642).png


محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۰:۳۸

محمد جان

شما در واقع با اینکار میاید مقادیر رو ست میکنید و مجدد کلاس رو برمیگردونید تا مورد اسفاده قرار بگیره و معادل این هست در واقع:

$mobile->setname('name');
$mobile->setoperating('name');
احمدرضا فاطمی کیا ۰۷ بهمن ۱۴۰۱، ۱۱:۴۵

من راستش بازم متوجه نشدم

چرا باید با گذشتن این تیکه کد،

return $this;

اجازه ست کردن به این روش داده بشه؟

cd86-Screenshot (645).png

محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۲:۰۱

این تکه کد میاد کلاس رو مجدد بر میگردونه.

یه دامپ بگیر ازش متوجه میشی.

احمدرضا فاطمی کیا ۰۷ بهمن ۱۴۰۱، ۱۲:۰۳

دامپ گرفتم نشد.

فکر کنم بلد نیستم ازش دامپ بگیرم درست و حسابی a9a8-Screenshot (647).png

محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۲:۳۸

از متد setname دامپ بگیر.

احمدرضا فاطمی کیا ۰۷ بهمن ۱۴۰۱، ۱۲:۴۲

خب آره الان دقیقا خود کلاس رو برمیگردونه

پس یعنی این this به معنای اینه که میگه بعد از اینکه مثلا فلان اسم رو ست کردی، حالا بیا و خود کلاس رو هم برگردون

ولی آخه چه ربطی داره به این که ما بتونیم به صورت chaining متدهارو ست بکنیم؟؟؟؟

من نمیتونم درکش کنم.

محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۲:۵۰

بذار اینجوری توضیح بدم.

شما این کدو در نظر بگیرید:

$mobile->setname()->setoperating()->setfamily();

$mobile یک instance از کلاس Mobile شماست. اولین دستوری که اجرا میشه در کد بالا:

$mobile->setname()

اگر بخوایم به متد setoperation دسترسی داشته باشیم با آبجکتی از نوع کلاس Mobile میتونیم دسترسی بگیریم. داخل کلاس Mobile متغیر $this به آبجکت ساخته شده اشاره میکنه بنابراین اگر return اش کنیم خروجی میشینه جای عبارت. وقتی setname اجرا میشه return $this باعث میشه انگار مجدد خود $mobile رو خارج از کلاس داشته باشیم یعنی ادامه دستور بالا بعد setname به این شکل در میاد:

$mobile->setoperating()->setfamily();

در این مرحله setoperation اجرا میشه و مجدد return $this اجرا میشه و جایگزی میشه و این مرحله رو خواهیم داشت:

$mobile->setfamily();

و به همین صورت آخری اجرا میشه و تمام. بنابراین هرکجا خواستیم زنجیره وار کردن متد رو پیاده کنیم مثل query builder در دیتابیس و ... در نهایت باید خروجی به این شکل باشه که اون آبجکتو داشته باشیم چون فقط با آبجکتی که میسازیمه که میتونیم به بقیه متد‌ها و همچنین property‌ها دسترسی داشته باشیم. property چون اسمشو اوردم این معمولا بعنوان آخرین قطعه از زنجیر میاد ولی میتونه به طریقی پیاده شه که هر جایی بیاد. بعنوان مثال دو تا میارم:

class Test
{
    public $obj;
    
    public function __construct()
    {
        $this->obj = $this;
    }
    
    public function setname()
    {
        echo 'name' . PHP_EOL;
        return $this;
    }
    
    public function setage()
    {
        echo 'age' . PHP_EOL;
        return $this;
    }
}
$test = new Test();
$test->setname()->obj->setage();
class Test2
{
    public $obj;
    
    public function __construct()
    {
        $this->obj = new Test3();
    }
}
class Test3
{
    public $obj;
    
    public function end()
    {
        echo 'end';
    }
}
$test2 = new Test2();
$test2->obj->end();
محسن موحد ۰۷ بهمن ۱۴۰۱، ۱۲:۵۲

من اینطوری متوجه شدم:‌

$mobile->setname()->setoperating()->setfamily();

یعنی در ابتدا setName اجرا میشه

بعد به خاطر ریترن کردن this، در setName، یه آبجکت دیگه از نوع موبایل، انگار قرار میگیره توی setName و ما میتونیم دوباره بگیم از اون آبجکت، حالا setOperating رو صدا بزن.

به همین نحو، setOerating هم به خاطر وجود this درون خودش، حامل یک شی از کلاس خودش میشه و ما ازهمین استفاده میکنیم و متد setFamily اون رو صدا میزنیم.

در صورت درست بودن حرفهای بالام، یه سوال برای من پیش میاد:‌

class Test
{
    public $obj;
    
    public function __construct()
    {
        $this->obj = $this;
    }
    
    public function setname()
    {
        echo 'name' . PHP_EOL;
        return $this;
    }
    
    public function setage()
    {
        echo 'age' . PHP_EOL;
        return $this;
    }
}
$test = new Test();
$test->setname()->obj->setage();

در construct گفتید که پراپرتی obj برابر با کلاس خودشه. و به همین خاطره که میشه بعد از اون هم دوباره به یک متد اشاره کرد.

ولی حالا ما چطوری باید خود اون پراپرتی obj رو مقدار دهیش کنیم؟؟؟


محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۶:۲۸

داخل setName قرار نمیگیره بلکه هر کدی که داخل این متد هستو ابتدا تفسیر میکنه و بعد $this رو برمیگردونه و انگار خودش حذف میشه و زنجیر از $mobile مسیرش ادامه پیدا میکنه به setOerating که بعدی اجرا بشه.(البته احتمالا منظور شما هم همین جمله ایه که من نوشتم منتها خواستم از لحاظ نگارشی هم درستش کنم)

چرا باید مقدار دهیش کنیم؟ پراپرتی هارو خودمون با هدفی که در ذهن داریم، پیاده میکنیم. هدف من از ساخت obj این بوده که آبجکت رو نگه داره اگر نیاز به نگه داشتن متغیرهای دیگه ای دارم، پراپرتی‌های دیگه ای میسازم. ببینید براساس هدفی که داریم همه چیز رو مینویسیم و اضافه میکنیم و یک سناریو رو میتونیم به روش‌های مختلفی پیاده کنیم. بستگی داره چی میخوام پیاده کنم. lیه مثال میارم که همه چیزو باهم قاطی کردم که متوجه بشی هر کاری میشه انجام داد، باید ببینیم چی میخوایم:

class Test1
{
    public $fields;
    private $name;
    
    public function __construct($name = null)
    {
        $this->fields = [
                't1' => $this,
                'id' => 123,
                'title' => 'm1',
                't2' => null
            ];
        
        $this->name = $name;
    }
    
    public function __get($fieldName) {
        if(isset($this->fields[$fieldName])) {
            return $this->fields[$fieldName];
        }
        return null;
    }
    
    public function __set($fieldName, $value) {
        if(array_key_exists($fieldName, $this->fields)) {
            $this->fields[$fieldName] = $value;
        }
    }
    
    public function display()
    {
        echo 'diplay' . PHP_EOL;
    }
}
class Test2
{
    public function display()
    {
        echo 'display2';
    }
}
$test = new Test1();
$test->fields['t1']->display();
$test->t1->display();
$test->t2 = new Test2();
$test->t2->display();

نکته: معمولا توو همچین پیاده سازی هایی که setter , getter داریم فیلد $fields بصورت private تعریف میشه که من برای اوردن مثال‌های مختلف بصورت public اوردم.

محسن موحد ۰۷ بهمن ۱۴۰۱، ۱۶:۵۷

آها الان جا افتاد

فقط یه سوال کوچیک

$test->fields['t1']->display();
$test->t1->display();

خب مشخصه که این دو با همدیگه برابرند چون شما t1 رو برابر با خود کلاس قرارش دادید

ولی سوال اینجاست که چه اتفاقی افتاد که تونستید مستقیم به t1 بگید متد display رو بده؟

الان t1 به عنوان چی داره قلمداد میشه؟؟؟؟؟

محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۷:۱۴

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

محسن موحد ۰۷ بهمن ۱۴۰۱، ۱۷:۱۷

t1 میاد عملیاتش رو روی کلاس انجام میده و کلاسی که عملیات روش انجام شده رو در اختیار شما قرار میده.

احمدرضا فاطمی کیا ۰۷ بهمن ۱۴۰۱، ۱۷:۱۷
    public function __construct($name = null)
    {
        $this->fields = [
                't1' => $this,
                'id' => 123,
                'title' => 'm1',
                't2' => null
            ];
        
        $this->name = $name;
    }
    
    public function __get($fieldName) {
        if(isset($this->fields[$fieldName])) {
            return $this->fields[$fieldName];
        }
        return null;
    }

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

انگار گفتیم return $this

ولی اینو نمیفهمم که چی شد که مستقیم تونستیم از $test به t1 دسترسی داشته باشیم.

$test->t1->display();


محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۷:۲۷

جواب سؤالت همینجاست:

"آهااا الان اینجا توی گتر گفتید که اگر t1 درون اون لیست وجود داشت، بیا و ومقدارشو ریترن کن.

انگار گفتیم return $this"


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

echo $test->id; // 123
echo $test->title; // m1
var_dump($test->t1); // this is an OBJECT
echo PHP_EOL;
echo $test->t1 instanceof Test1; // true

در مثال اولی که اوردی یک متغیر داشتی به اسم $mobile الان اگر کلاس Test1 رو کلاس Mobile در نظر بگیریم(فرض کنیم)، این دو عبارت باهم برابرن:

$test->t1 == $mobile

مسئله زمان رو هم در نظر بگیرید، چند روز دیگه این پیاده سازی هارو بهتر از الان درک میکنید.

بازم هرجاییش گنگه بگید تا مثال بیشتری بیارم. (چون خیلی تنوع دادم و چند مدل پیاده سازی رو در کنار هم اوردم ممکنه بعضی چیزا تازگی داشته باشه.)

محسن موحد ۰۷ بهمن ۱۴۰۱، ۱۷:۳۴

ممنونم آقای موحد. فکر میکنم متوجه‌ش شدم.

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

مجدد تمرین میکنم، اگر اشکالی بود در همین تاپیک میپرسم سوالمو

تشکر که باصبوری پاسخ دادید

احمدرضا جان از شمام ممنونم

محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۷:۴۸

خواهش میکنم. سؤالی بود درخدمتم.

محسن موحد ۰۷ بهمن ۱۴۰۱، ۱۷:۵۲

میشه ببینید این ارور برای چیه؟؟؟؟؟؟

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

b821-Screenshot (650).png

محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۸:۵۷

شما با آبجکت اومدید مثل یک string برخورد کردید:

لاین 35 عبارتی که return میشه رو با PHP_EOL کانکت کردید. بنابراین مفسر باید آبجکتو به رشته cast کنه که با این خطا روبرو میشه.

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

بهترین پاسخ
محسن موحد ۰۷ بهمن ۱۴۰۱، ۱۹:۲۵

اکی شد متشکرم

الان کاملا این مبحث جا افتاد

ممنونم از وقتی که گذاشتید

محمدجوکار ۰۷ بهمن ۱۴۰۱، ۱۹:۳۹