سؤال

في PHP 5، ما هو الفرق بين استخدام self و $this?

متى يكون كل منها مناسبا؟

هل كانت مفيدة؟

المحلول

اجابة قصيرة

يستخدم $this للإشارة إلى الكائن الحالي.يستخدم self للإشارة إلى الفئة الحالية.وبعبارة أخرى، استخدم $this->member للأعضاء غير الأساسيين ، والاستخدام self::$member للأعضاء الساكنة.

الإجابة الكاملة

هنا مثال على صحيح استخدام $this و self لمتغيرات الأعضاء غير الثابتة والثابتة:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?>

هنا مثال على غير صحيح استخدام $this و self لمتغيرات الأعضاء غير الثابتة والثابتة:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo self::$non_static_member . ' '
           . $this->static_member;
    }
}

new X();
?>

هنا مثال على تعدد الأشكال مع $this لوظائف الأعضاء:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        $this->foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

هنا مثال على قمع السلوك متعدد الأشكال باستخدام self لوظائف الأعضاء:

<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        self::foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>

الفكرة هي أن $this->foo() يدعو foo() وظيفة العضو مهما كان النوع الدقيق للكائن الحالي.إذا كان الكائن من type X, ، هكذا يدعو X::foo().إذا كان الكائن من type Y, ، يدعو Y::foo().لكن مع self::foo(), X::foo() يسمى دائما.

من http://www.phpbuilder.com/board/showthread.php?t=10354489:

بواسطة http://board.phpbuilder.com/member.php?145249-laserlight

نصائح أخرى

الكلمة الرئيسية "الذات" تفعل ذلك لا قم بالإشارة فقط إلى "الفئة الحالية"، على الأقل ليس بطريقة تقيدك بالأعضاء الثابتين.في سياق عضو غير ثابت، self يوفر أيضًا طريقة لتجاوز vtable (راجع الويكي على vtable) للكائن الحالي.تماما كما يمكنك استخدامها parent::methodName() لاستدعاء نسخة الوالدين من وظيفة، حتى تتمكن من الاتصال self::methodName() لاستدعاء تطبيق الفئات الحالية للطريقة.

class Person {
    private $name;

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

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

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();

سيؤدي هذا إلى إخراج:

مرحبًا، أنا لودفيج المهوس
وداعا من لودفيج الشخص

sayHello() يستخدم $this المؤشر، لذلك يتم استدعاء vtable للاتصال Geek::getTitle(). sayGoodbye() الاستخدامات self::getTitle(), ، لذلك لا يتم استخدام vtable، و Person::getTitle() يسمى.في كلتا الحالتين، نحن نتعامل مع طريقة كائن تم إنشاء مثيل له، ولدينا إمكانية الوصول إلى $this المؤشر ضمن الوظائف المطلوبة.

لا تستخدم self::, ، يستخدم static::

هناك جانب آخر للذات::وهذا أمر جدير بالذكر.بشكل مزعج self:: يشير إلى النطاق عند نقطة التعريف وليس عند نقطة التنفيذ.خذ بعين الاعتبار هذه الفئة البسيطة بطريقتين:

class Person
{

    public static function status()
    {
        self::getStatus();
    }

    protected static function getStatus()
    {
        echo "Person is alive";
    }

}

إذا اتصلنا Person::status() سوف نرى "الشخص على قيد الحياة".الآن فكر فيما يحدث عندما ننشئ فصلًا يرث من هذا:

class Deceased extends Person
{

    protected static function getStatus()
    {
        echo "Person is deceased";
    }

}

الاتصال Deceased::status() نتوقع أن نرى "الشخص متوفى" ولكن ما نراه هو "الشخص على قيد الحياة" حيث يحتوي النطاق على تعريف الطريقة الأصلية عند الاتصال بـ self::getStatus() تم تعريفه.

PHP 5.3 لديه الحل.ال static:: ينفذ مشغل الدقة "الربط الثابت المتأخر" وهي طريقة رائعة للقول إنه مرتبط بنطاق الفئة المسماة.تغيير الخط في status() ل static::getStatus() والنتائج هي ما تتوقعه.في الإصدارات الأقدم من PHP، سيتعين عليك العثور على حيلة للقيام بذلك.

يرى وثائق PHP

لذا فإن الإجابة على السؤال ليست كما طرحت ...

$this-> يشير إلى الكائن الحالي (مثيل لفئة)، في حين أن static:: يشير إلى فئة

لفهم ما نتحدث عنه حقًا عندما نتحدث عنه self عكس $this, ، نحن بحاجة إلى التعمق في ما يحدث على المستوى المفاهيمي والعملي.لا أشعر حقًا أن أيًا من الإجابات تفعل ذلك بشكل مناسب، لذا فهذه محاولتي.

لنبدأ بالحديث عن ما أ فصل و هدف يكون.

الطبقات والكائنات، من الناحية المفاهيمية

وماذا في ذلك يكون أ فصل؟يعرفه الكثير من الناس على أنه مخطط أو أ نموذج لكائن.في الواقع، يمكنك قراءة المزيد حول الفصول في PHP هنا.وإلى حد ما هذا ما هو عليه حقا.دعونا نلقي نظرة على الفصل:

class Person {
    public $name = 'my name';
    public function sayHello() {
        echo "Hello";
    }
}

كما يمكنك أن تقول، هناك خاصية في تلك الفئة تسمى $name وطريقة (وظيفة) تسمى sayHello().

إنه جداً من المهم أن نلاحظ أن فصل هو هيكل ثابت.وهو ما يعني أن الطبقة Person, ، بمجرد تعريفها، تكون دائمًا هي نفسها في كل مكان تنظر إليه.

الكائن من ناحية أخرى هو ما يسمى مثال من فئة.ما يعنيه ذلك هو أننا نأخذ "مخطط" الفصل ونستخدمه لعمل نسخة ديناميكية.أصبحت هذه النسخة الآن مرتبطة بشكل خاص بالمتغير الذي تم تخزينها فيه.ولذلك، فإن أي تغييرات على مثال محلي لتلك الحالة.

$bob = new Person;
$adam = new Person;
$bob->name = 'Bob';
echo $adam->name; // "my name"

نحن نصنع الجديد الحالات من فئة باستخدام new المشغل أو العامل.

لذلك، نقول أن الفئة هي بنية عالمية، والكائن هو بنية محلية.لا تقلق بشأن ذلك المضحك -> بناء الجملة، ونحن في طريقنا للذهاب إلى ذلك قليلا.

هناك شيء آخر يجب أن نتحدث عنه، وهو أننا نستطيع ذلك يفحص إذا كان المثيل هو instanceof فئة معينة: $bob instanceof Person الذي يُرجع قيمة منطقية إذا كان $bob تم إجراء المثيل باستخدام Person فصل، أو طفل من Person.

تعريف الدولة

لذلك دعونا نتعمق قليلاً في ما يحتويه الفصل بالفعل.هناك 5 أنواع من "الأشياء" التي يحتوي عليها الفصل:

  1. ملكيات - فكر في هذه كمتغيرات سيحتوي عليها كل مثيل.

    class Foo {
        public $bar = 1;
    }
    
  2. خصائص ثابتة - فكر في هذه كمتغيرات مشتركة على مستوى الفصل.وهذا يعني أنه لا يتم نسخها أبدًا في كل حالة.

    class Foo {
        public static $bar = 1;
    }
    
  3. طُرق - هذه هي الوظائف التي سيحتوي عليها كل مثيل (وتعمل على المثيلات).

    class Foo {
        public function bar() {}
    }
    
  4. الأساليب الثابتة - هذه هي الوظائف التي يتم مشاركتها عبر الفصل بأكمله.إنهم يفعلون لا تعمل على المثيلات، ولكن بدلاً من ذلك على الخصائص الثابتة فقط.

    class Foo {
        public static function bar() {}
    }
    
  5. الثوابت - حل الطبقة الثوابت.لن أتعمق أكثر هنا، ولكن أضف للاكتمال:

    class Foo {
        const BAR = 1;
    }
    

لذلك، نقوم بشكل أساسي بتخزين المعلومات في حاوية الفئة والكائن باستخدام "تلميحات" حولها ثابتة والتي تحدد ما إذا كانت المعلومات مشتركة (وبالتالي ثابتة) أم لا (وبالتالي ديناميكية).

الدولة والأساليب

داخل الطريقة، يتم تمثيل مثيل الكائن بواسطة $this عامل.الحالة الحالية لهذا الكائن موجودة، وتغيير (تغيير) أي خاصية سيؤدي إلى تغيير في ذلك المثيل (ولكن ليس في الآخرين).

إذا تم استدعاء الطريقة بشكل ثابت، فإن $this عامل غير محدد.وذلك لأنه لا يوجد مثيل مرتبط بمكالمة ثابتة.

الشيء المثير للاهتمام هنا هو كيفية إجراء المكالمات الثابتة.لذلك دعونا نتحدث عن كيفية وصولنا إلى الدولة:

دولة الوصول

والآن بعد أن قمنا بتخزين تلك الحالة، نحتاج إلى الوصول إليها.قد يكون هذا صعبًا بعض الشيء (أو طريق أكثر من قليل)، لذلك دعونا نقسم هذا إلى وجهتي نظر:من خارج مثيل/فئة (على سبيل المثال من استدعاء دالة عادية، أو من النطاق العام)، وداخل مثيل/فئة (من داخل طريقة على الكائن).

من خارج المثيل/الفئة

من خارج المثيل/الفئة، قواعدنا بسيطة جدًا ويمكن التنبؤ بها.لدينا عاملين، ويخبرنا كل منهما على الفور إذا كنا نتعامل مع مثيل أو فئة ثابتة:

  • -> - مشغل الكائن - يتم استخدام هذا دائمًا عندما نصل إلى مثيل.

    $bob = new Person;
    echo $bob->name;
    

    من المهم ملاحظة أن الاتصال Person->foo لا معنى له (منذ Person هو فئة، وليس مثال).لذلك، هذا خطأ تحليلي.

  • :: - نطاق القرار المشغل - يُستخدم هذا دائمًا للوصول إلى خاصية أو أسلوب ثابت للفئة.

    echo Foo::bar()
    

    بالإضافة إلى ذلك، يمكننا استدعاء طريقة ثابتة على كائن بنفس الطريقة:

    echo $foo::bar()
    

    إنه لأقصى حد من المهم أن نلاحظ أنه عندما نفعل هذا من الخارج, ، يتم إخفاء مثيل الكائن من bar() طريقة.بمعنى أنه نفس التشغيل تمامًا:

    $class = get_class($foo);
    $class::bar();
    

لذلك، $this لم يتم تعريفه في المكالمة الثابتة.

من داخل مثيل/فئة

الأمور تتغير قليلا هنا.يتم استخدام نفس عوامل التشغيل، لكن معناها يصبح غير واضح إلى حد كبير.

ال مشغل الكائن -> لا يزال يُستخدم لإجراء مكالمات إلى حالة مثيل الكائن.

class Foo {
    public $a = 1;
    public function bar() {
        return $this->a;
    }
}

استدعاء bar() طريقة على $foo (مثال Foo) باستخدام مشغل الكائن: $foo->bar() سيؤدي إلى إصدار المثيل لـ $a.

هكذا نتوقع.

معنى :: المشغل على الرغم من التغييرات.يعتمد ذلك على سياق استدعاء الوظيفة الحالية:

  • ضمن سياق ثابت

    ضمن سياق ثابت، أي مكالمات يتم إجراؤها باستخدام :: سوف تكون ثابتة أيضًا.لنلقي نظرة على مثال:

    class Foo {
        public function bar() {
            return Foo::baz();
        }
        public function baz() {
            return isset($this);
        }
    }
    

    الاتصال Foo::bar() سوف يدعو baz() طريقة ثابتة، وبالتالي $this سوف لا تكون مأهولة بالسكان.تجدر الإشارة إلى أنه في الإصدارات الأخيرة من PHP (5.3+) سيؤدي هذا إلى ظهور خطأ E_STRICT خطأ، لأننا نطلق على الأساليب غير الثابتة بشكل ثابت.

  • ضمن سياق المثال

    من ناحية أخرى، ضمن سياق المثيل، يتم إجراء المكالمات باستخدام :: تعتمد على متلقي المكالمة (الطريقة التي نتصل بها).إذا تم تعريف الطريقة على أنها static, ، فسوف يستخدم مكالمة ثابتة.إذا لم يكن الأمر كذلك، فسيتم إعادة توجيه معلومات المثيل.

    لذا، بالنظر إلى الكود أعلاه، اتصل $foo->bar() سيعود true, ، نظرًا لأن الاستدعاء "الثابت" يحدث داخل سياق المثيل.

منطقي؟لا أعتقد ذلك.انه مربك.

الكلمات الرئيسية المختصرة

نظرًا لأن ربط كل شيء معًا باستخدام أسماء الفئات أمر سيئ إلى حد ما، توفر PHP 3 كلمات رئيسية "اختصارية" أساسية لتسهيل حل النطاق.

  • self - يشير هذا إلى اسم الفصل الحالي.لذا self::baz() بالضبط مثل Foo::baz() في حدود Foo الفئة (أي طريقة عليها).

  • parent - يشير هذا إلى والد الفصل الحالي.

  • static - يشير هذا إلى الفئة المسماة.بفضل الميراث، يمكن للفئات الفرعية تجاوز الأساليب والخصائص الثابتة.لذلك اتصل بهم باستخدام static بدلاً من اسم الفئة يسمح لنا بتحديد مصدر المكالمة، بدلاً من المستوى الحالي.

أمثلة

أسهل طريقة لفهم ذلك هي البدء في النظر إلى بعض الأمثلة.دعونا نختار فئة:

class Person {
    public static $number = 0;
    public $id = 0;
    public function __construct() {
        self::$number++;
        $this->id = self::$number;
    }
    public $name = "";
    public function getName() {
        return $this->name;
    }
    public function getId() {
        return $this->id;
    }
}

class Child extends Person {
    public $age = 0;
    public function __construct($age) {
        $this->age = $age;
        parent::__construct();
    }
    public function getName() {
        return 'child: ' . parent::getName();
    }
}

الآن، نحن ننظر أيضًا إلى الميراث هنا.تجاهل للحظة أن هذا نموذج كائن سيئ، ولكن دعونا ننظر إلى ما يحدث عندما نلعب بهذا:

$bob = new Person;
$bob->name = "Bob";
$adam = new Person;
$adam->name = "Adam";
$billy = new Child;
$billy->name = "Billy";
var_dump($bob->getId()); // 1
var_dump($adam->getId()); // 2
var_dump($billy->getId()); // 3

لذلك تتم مشاركة عداد المعرفات عبر كلا الحالتين والأطفال (لأننا نستخدم self للوصول إليه.لو استخدمنا static, ، يمكننا تجاوزه في فئة الأطفال).

var_dump($bob->getName()); // Bob
var_dump($adam->getName()); // Adam
var_dump($billy->getName()); // child: Billy

لاحظ أننا نقوم بتنفيذ Person::getName() مثال طريقة في كل مرة.لكننا نستخدم parent::getName() للقيام بذلك في إحدى الحالات (الحالة التابعة).وهذا ما يجعل هذا النهج قويا.

كلمة تحذير #1

لاحظ أن سياق الاستدعاء هو الذي يحدد ما إذا كان سيتم استخدام المثيل أم لا.لذلك:

class Foo {
    public function isFoo() {
        return $this instanceof Foo;
    }
}

ليس دائماً حقيقي.

class Bar {
    public function doSomething() {
        return Foo::isFoo();
    }
}
$b = new Bar;
var_dump($b->doSomething()); // bool(false)

الآن هو عليه حقًا غريب هنا.نحن ندعو فئة مختلفة، ولكن $this الذي يتم تمريره إلى Foo::isFoo() الطريقة هي مثال $bar.

يمكن أن يتسبب هذا في حدوث جميع أنواع الأخطاء وWTF-ery المفاهيمي.لذلك أقترح بشدة تجنب :: عامل التشغيل من داخل أساليب المثيل على أي شيء باستثناء تلك الكلمات الرئيسية الافتراضية "المختصرة" الثلاث (static, self, ، و parent).

كلمة تحذير #2

لاحظ أن الأساليب والخصائص الثابتة تتم مشاركتها من قبل الجميع.وهذا يجعلها متغيرات عالمية بشكل أساسي.مع كل نفس المشاكل التي تأتي مع العوالم.لذلك سأكون مترددًا حقًا في تخزين المعلومات في الأساليب/الخصائص الثابتة ما لم تكن مرتاحًا لكونها عالمية حقًا.

كلمة تحذير #3

بشكل عام، ستحتاج إلى استخدام ما يعرف بالربط المتأخر الثابت باستخدام static بدلاً من self.لكن لاحظ أنهما ليسا نفس الشيء، لذلك قول "استخدم دائمًا static بدلاً من self هو حقا قصير النظر.بدلاً من ذلك، توقف وفكر في المكالمة التي تريد إجراؤها وفكر إذا كنت تريد أن تتمكن فصول الأطفال من تجاوز ذلك حل ثابت يتصل.

ليرة تركية/د

من المؤسف أن ترجع وتقرأهربما يكون طويلاً للغاية، ولكنه طويل جدًا لأن هذا موضوع معقد

تل/دكتور #2

حسنا جيد.باختصار، self يستخدم للإشارة اسم الفئة الحالية داخل الفصل، حيث $this يشير إلى الكائن الحالي مثال.لاحظ أن self هو اختصار للنسخ/اللصق.يمكنك استبداله بأمان باسم صفك، وسيعمل بشكل جيد.لكن $this هو متغير ديناميكي لا يمكن تحديده مسبقًا (وربما لا يكون صفك).

تل/دكتور #3

إذا تم استخدام مشغل الكائن (->)، ثُم أنت دائماً أعلم أنك تتعامل مع مثال.إذا تم استخدام عامل دقة النطاق (::)، أنت بحاجة إلى مزيد من المعلومات حول السياق (هل نحن في سياق كائن بالفعل؟هل نحن خارج الكائن؟إلخ).

self (وليس $self) يشير إلى يكتب من الطبقة، حيث $this يشير إلى الحالي مثال الطبقة. self مخصص للاستخدام في وظائف الأعضاء الثابتة للسماح لك بالوصول إلى متغيرات الأعضاء الثابتة. $this يتم استخدامه في وظائف الأعضاء غير الثابتة، وهو مرجع إلى مثيل الفئة التي تم استدعاء وظيفة العضو عليها.

لأن this هو كائن، يمكنك استخدامه مثل: $this->member

لأن self ليس كائنًا، إنه في الأساس نوع يشير تلقائيًا إلى الفئة الحالية، يمكنك استخدامه مثل: self::member

$this-> يُستخدم للإشارة إلى مثيل محدد لمتغيرات الفصل (متغيرات الأعضاء) أو الأساليب.

Example: 
$derek = new Person();

أصبح $derek الآن مثيلًا محددًا لـ Person.كل شخص لديه اسم أول واسم عائلة، ولكن $derek لديه اسم أول واسم عائلة محددين (ديريك مارتن).داخل مثيل $derek، يمكننا الإشارة إلى تلك بـ $this->first_name و$this->last_name

اسم الفئة::يستخدم للإشارة إلى هذا النوع من الفئة ومتغيراتها الثابتة والأساليب الثابتة.إذا كان ذلك مفيدًا، فيمكنك استبدال كلمة "ثابت" عقليًا بكلمة "مشتركة".نظرًا لأنها مشتركة، فلا يمكنها الإشارة إلى $this، الذي يشير إلى مثيل محدد (غير مشترك).المتغيرات الثابتة (أي.يمكن مشاركة $db_connection الثابت) بين جميع مثيلات نوع الكائن.على سبيل المثال، تشترك كافة كائنات قاعدة البيانات في اتصال واحد (اتصال $ ثابت).

مثال المتغيرات الثابتة:لنفترض أن لدينا فئة قاعدة بيانات تحتوي على متغير عضو واحد:ثابت $num_connections؛الآن ضع هذا في المنشئ:

function __construct()
{
    if(!isset $num_connections || $num_connections==null)
    {
        $num_connections=0;
    }
    else
    {
        $num_connections++;
    }
}

مثلما تحتوي الكائنات على عناصر إنشاء، فإن لديها أيضًا أدوات تدمير، والتي يتم تنفيذها عندما يموت الكائن أو لا يتم تعيينه:

function __destruct()
{
    $num_connections--;
}

في كل مرة نقوم بإنشاء مثيل جديد، سيؤدي ذلك إلى زيادة عداد الاتصال الخاص بنا بمقدار واحد.في كل مرة ندمر فيها مثيلًا أو نتوقف عن استخدامه، سيؤدي ذلك إلى تقليل عداد الاتصال بمقدار واحد.بهذه الطريقة، يمكننا مراقبة عدد مثيلات كائن قاعدة البيانات الذي نستخدمه مع:

echo DB::num_connections;

نظرًا لأن $num_connections ثابت (مشترك)، فإنه سيعكس العدد الإجمالي لكائنات قاعدة البيانات النشطة.ربما تكون قد شاهدت هذه التقنية المستخدمة لمشاركة اتصالات قاعدة البيانات بين كافة مثيلات فئة قاعدة البيانات.ويتم ذلك لأن إنشاء اتصال قاعدة البيانات يستغرق وقتًا طويلاً، لذا من الأفضل إنشاء اتصال واحد فقط ومشاركته (وهذا ما يسمى بنمط Singleton).

الطرق الثابتة (أييمكن استخدام العرض الثابت العام::format_phone_number($digits)) دون إنشاء مثيل لأحد هذه الكائنات أولاً (أيلا يشيرون داخليًا إلى $this).

مثال على الطريقة الثابتة:

public static function prettyName($first_name, $last_name)
{
    echo ucfirst($first_name).' '.ucfirst($last_name);
}

echo Person::prettyName($derek->first_name, $derek->last_name);

كما ترون، الدالة الثابتة العامة beautifulName لا تعرف شيئًا عن الكائن.إنها تعمل فقط مع المعلمات التي تمررها، مثل وظيفة عادية ليست جزءًا من كائن.لماذا نهتم إذن، إذا كان بإمكاننا أن نجعله ليس جزءًا من الشيء؟

  1. أولاً، يساعدك ربط الوظائف بالكائنات في الحفاظ على تنظيم الأشياء، حتى تعرف مكان العثور عليها.
  2. ثانياً، يمنع تعارض الأسماء.في المشروع الكبير، من المحتمل أن يكون لديك مطوران يقومان بإنشاء وظائف getName().إذا قام أحدهما بإنشاء ClassName1::getName()، وقام الآخر بإنشاء ClassName2::getName()، فلا توجد مشكلة على الإطلاق.لا يوجد صراع.ياي أساليب ثابتة!

الذات::إذا كنت تقوم بالترميز الخارج الكائن الذي يحتوي على الطريقة الثابتة التي تريد الإشارة إليها، يجب عليك الاتصال به باستخدام اسم الكائن View::format_phone_number($phone_number);إذا كنت تقوم بالترميز داخل الكائن الذي يحتوي على الطريقة الثابتة التي تريد الرجوع إليها، يمكنك ذلك أيضاً استخدم اسم الكائن View::format_phone_number($pn)، أو يمكنك استخدام الاختصار self::format_phone_number($pn)

الأمر نفسه ينطبق على المتغيرات الثابتة:مثال: عرض::templates_path مقابل الذات::templates_path

داخل فئة قاعدة البيانات، إذا كنا نشير إلى طريقة ثابتة لبعض الكائنات الأخرى، فسنستخدم اسم الكائن:مثال: جلسة::getUsersOnline();

ولكن إذا أرادت فئة قاعدة البيانات الإشارة إلى المتغير الثابت الخاص بها، فستقول فقط self:مثال: الذات::اتصال؛

آمل ان هذا أوضح الأمور :)

من هذا بلوق وظيفة:

  • self يشير إلى الفصل الحالي
  • self يمكن استخدامها لاستدعاء الوظائف الثابتة والإشارة إلى متغيرات الأعضاء الثابتة
  • self يمكن استخدامها داخل وظائف ثابتة
  • self يمكن أيضًا إيقاف تشغيل السلوك متعدد الأشكال عن طريق تجاوز vtable
  • $this يشير إلى الكائن الحالي
  • $this يمكن استخدامها لاستدعاء وظائف ثابتة
  • $this لا ينبغي أن تستخدم لاستدعاء متغيرات الأعضاء الثابتة.يستخدم self بدلاً من.
  • $this لا يمكن استخدامها داخل الوظائف الثابتة

في PHP، يمكنك استخدام الكلمة الأساسية self للوصول إلى الخصائص والأساليب الثابتة.

المشكلة هي أنه يمكنك استبدال $this->method() مع self::method()في أي مكان، بغض النظر عما إذا كان method() أعلن ثابت أم لا.إذن أي واحد يجب أن تستخدمه؟

خذ بعين الاعتبار هذا الرمز:

class ParentClass {
    function test() {
        self::who();    // will output 'parent'
        $this->who();   // will output 'child'
    }

    function who() {
        echo 'parent';
    }
}

class ChildClass extends ParentClass {
    function who() {
        echo 'child';
    }
}

$obj = new ChildClass();
$obj->test();

في هذا المثال، self::who() سيتم دائمًا إخراج "الأصل"، بينما $this->who() سوف يعتمد على فئة الكائن.

الآن يمكننا أن نرى أن الذات تشير إلى الفئة التي تسمى فيها، while $this بالعودة الى فئة الكائن الحالي.

لذلك، يجب عليك استخدام الذات فقط عندما $this غير متوفر، أو عندما لا تريد السماح للفئات التابعة بالكتابة فوق الطريقة الحالية.

داخل تعريف الفئة، يشير $this إلى الكائن الحالي، بينما يشير self إلى الفئة الحالية.

من الضروري الإشارة إلى عنصر فئة باستخدام self، والإشارة إلى عنصر كائن باستخدام $this.

self::STAT // refer to a constant value
self::$stat // static variable
$this->stat // refer to an object variable  

فيما يلي مثال على الاستخدام الصحيح لـ $ this and self للمتغيرات الأعضاء غير الاصطناعية والستاتية:

<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?> 

وفق http://www.php.net/manual/en/language.oop5.static.php لا يوجد $self.هناك فقط $this, ، للإشارة إلى المثيل الحالي للفئة (الكائن)، والذات، والتي يمكن استخدامها للإشارة إلى الأعضاء الثابتين للفئة.الفرق بين مثيل الكائن والفئة يلعب هنا.

self يشير إلى الفئة الحالية (التي يطلق عليها)،

$this يشير إلى الكائن الحالي.يمكنك استخدام ثابت بدلا من الذات.انظر المثال:

    class ParentClass {
            function test() {
                    self::which();  // output 'parent'
                    $this->which(); // output 'child'
            }

            function which() {
                    echo 'parent';
            }
    }

    class ChildClass extends ParentClass {
            function which() {
                    echo 'child';
            }
    }

    $obj = new ChildClass();
    $obj->test();

انتاج:الطفل الوالد

  • يشير مؤشر الكائن $this إلى الكائن الحالي.
  • تشير قيمة الفئة "ثابت" إلى الكائن الحالي.
  • تشير قيمة الفئة "self" إلى الفئة المحددة التي تم تعريفها فيها.
  • تشير قيمة الفئة "الأصل" إلى الأصل للفئة المحددة التي تم تعريفها فيها.

انظر المثال التالي الذي يوضح التحميل الزائد.

<?php

class A {

    public static function newStaticClass()
    {
        return new static;
    }

    public static function newSelfClass()
    {
        return new self;
    }

    public function newThisClass()
    {
        return new $this;
    }
}

class B extends A
{
    public function newParentClass()
    {
        return new parent;
    }
}


$b = new B;

var_dump($b::newStaticClass()); // B
var_dump($b::newSelfClass()); // A because self belongs to "A"
var_dump($b->newThisClass()); // B
var_dump($b->newParentClass()); // A


class C extends B
{
    public static function newSelfClass()
    {
        return new self;
    }
}


$c = new C;

var_dump($c::newStaticClass()); // C
var_dump($c::newSelfClass()); // C because self now points to "C" class
var_dump($c->newThisClass()); // C
var_dump($b->newParentClass()); // A because parent was defined *way back* in class "B"

في معظم الأوقات تريد الإشارة إلى الفصل الحالي ولهذا السبب تستخدمه static أو $this.ومع ذلك، هناك أوقات عندما يحتاج self لأنك تريد الصف الأصلي بغض النظر عما يمتد إليه.(جدا، نادرا جدا)

بما أنه لم يتحدث أحد هنا عن الأداء، فإليك معيارًا صغيرًا قمت به (5.6):

 Name     | Time    | Percent  
----------|---------|---------  
 $this->  | 0.99163 | 106.23%  
 self::   | 0.96912 | 103.82%  
 static:: | 0.93348 | 100%

هذه هي نتائج 2000000 عملية تشغيل، وإليك الكود الذي استخدمته:

<?php

require '../vendor/autoload.php';

// My small class to do benchmarks
// All it does is looping over every test x times and record the
//   time it takes using `microtime(true)`
// Then, the percentage is calculated, with 100% being the quickest
// Times are being rouned for outputting only, not to calculate the percentages
$b = new Tleb\Benchmark\Benchmark(2000000);

class Foo
{
    public function calling_this()
    {
        $this->called();
    }

    public function calling_self()
    {
        self::called();
    }

    public function calling_static()
    {
        static::called();
    }

    public static function called()
    {
    }
}

$b->add('$this->',  function () { $foo = new Foo; $foo->calling_this(); });
$b->add('self::',   function () { $foo = new Foo; $foo->calling_self(); });
$b->add('static::', function () { $foo = new Foo; $foo->calling_static(); });

$b->run();

أعتقد أن السؤال لم يكن ما إذا كان يمكنك الاتصال بالعضو الثابت في الفصل عن طريق الاتصال ClassName::staticMember.كان السؤال ما الفرق بين الاستخدام self::classmember و $this->classmember.

على سبيل المثال، يعمل كلا المثالين التاليين دون أي أخطاء، سواء كنت تستخدمه self:: أو $this->

class Person{
    private $name;
    private $address;

    public function __construct($new_name,$new_address){
        $this->name = $new_name;
        $this->address = $new_address;
    }
}

class Person{
    private $name;
    private $address;
    public function __construct($new_name,$new_address){
        self::$name = $new_name;
        self::$address = $new_address;
    }
}

متى self يستخدم مع :: يشير عامل التشغيل إلى الفئة الحالية، والتي يمكن القيام بها في سياقات ثابتة وغير ثابتة. $this يشير إلى الكائن نفسه.بالإضافة إلى ذلك، فهو قانوني تمامًا للاستخدام $this لاستدعاء الأساليب الثابتة (ولكن ليس للإشارة إلى الحقول).

$this يشير إلى كائن الفئة الحالية، self يشير إلى الفئة الحالية (ليس كائن).الفئة هي مخطط الكائن.لذا فإنك تحدد فئة، ولكنك تقوم ببناء كائنات.

بمعنى آخر، استخدم self for static و this for none-static members or methods.

أيضًا في سيناريو الطفل/الوالد self / parent يستخدم في الغالب لتحديد أعضاء الفصل من الأطفال والآباء والأساليب.

بالإضافة إلى ذلك منذ ذلك الحين $this:: لم تتم مناقشتها بعد.

لأغراض إعلامية فقط، اعتبارًا من PHP 5.3 عند التعامل مع الكائنات التي تم إنشاء مثيل لها للحصول على قيمة النطاق الحالية، بدلاً من استخدام static::, ، يمكن للمرء أن يستخدم بدلا من ذلك $this:: مثل ذلك.

http://ideone.com/7etRHy

class Foo
{
    const NAME = 'Foo';

    //Always Foo::NAME (Foo) due to self
    protected static $staticName = self::NAME;

    public function __construct()
    {
        echo $this::NAME;
    }

    public function getStaticName()
    {
       echo $this::$staticName;
    }
}

class Bar extends Foo
{
    const NAME = 'FooBar';

    /**
     * override getStaticName to output Bar::NAME
     */
    public function getStaticName()
    {
        $this::$staticName = $this::NAME;
        parent::getStaticName();
    }
}

$foo = new Foo; //outputs Foo
$bar = new Bar; //outputs FooBar
$foo->getStaticName(); //outputs Foo
$bar->getStaticName(); //outputs FooBar
$foo->getStaticName(); //outputs FooBar

إن استخدام الكود أعلاه ليس شائعًا أو ممارسات موصى بها ، ولكنه ببساطة هو توضيح استخدامه ، وهو أن يكون بمثابة أكثر من "هل تعلم؟" في إشارة إلى سؤال الملصق الأصلي.

كما أنه يمثل استخدام $object::CONSTANT على سبيل المثال echo $foo::NAME; في مقابل $this::NAME;

لقد واجهت نفس السؤال والإجابة البسيطة هي:

  • $هذا يتطلب مثيل للفئة
  • الذات:: لا

كلما كنت تستخدم أساليب ثابتة أو سمات ثابتة وتريد الاتصال بهم دون إنشاء كائن من الفئة التي تحتاج إلى استخدامها الذات:: لندعو لهم، لأن $هذا يتطلب دائمًا إنشاء الكائن.

يستخدم self إذا كنت تريد استدعاء أسلوب فئة دون إنشاء كائن/مثيل لتلك الفئة، وبالتالي حفظ كبش (أحيانًا استخدم الذات لهذا الغرض).وبعبارة أخرى، فإنه في الواقع يستدعي طريقة بشكل ثابت.يستخدم this لمنظور الكائن.

حالة 1:يستخدم self يمكن استخدامها لثوابت الطبقة

 class classA { 
     const FIXED_NUMBER = 4; 
     self::POUNDS_TO_KILOGRAMS
}

إذا كنت تريد الاتصال به خارج الفصل الدراسي، فاستخدم classA::POUNDS_TO_KILOGRAMS للوصول إلى الثوابت

الحالة 2:للخصائص الساكنة

class classC {
     public function __construct() { 
     self::$_counter++; $this->num = self::$_counter;
   }
}

وفقًا لـ php.net هناك ثلاث كلمات رئيسية خاصة في هذا السياق: self, parent و static.يتم استخدامها للوصول إلى الخصائص أو الأساليب من داخل تعريف الفئة.

$this, من ناحية أخرى، يتم استخدامه لاستدعاء مثيل وأساليب أي فئة طالما أن هذه الفئة يمكن الوصول إليها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top