खोज…


परिचय

इसी तरह के कार्यों को समूहीकृत करके अपने कोड को अधिक कुशल और कम दोहरावदार बनाने के लिए कक्षाओं और वस्तुओं का उपयोग किया जाता है।

ऑब्जेक्ट बनाने के लिए उपयोग किए जाने वाले कार्यों और डेटा संरचना को परिभाषित करने के लिए एक वर्ग का उपयोग किया जाता है। इस पूर्वनिर्धारित संरचना का उपयोग करके वस्तुओं का निर्माण किया जाता है।

वाक्य - विन्यास

  • class <ClassName> [ extends <ParentClassName> ] [ implements <Interface1> [, <Interface2>, ... ] { } // क्लास डिक्लेरेशन
  • interface <InterfaceName> [ extends <ParentInterface1> [, <ParentInterface2>, ...] ] { } // इंटरफ़ेस घोषणा का विस्तार
  • use <Trait1> [, <Trait2>, ...] ; // लक्षण का उपयोग करें
  • [ public | protected | private ] [ static ] $<varName>; // घोषणा घोषित करें
  • const <CONST_NAME>; // लगातार घोषणा
  • [ public | protected | private ] [ static ] function <methodName>([args...]) { } // विधि घोषणा

टिप्पणियों

कक्षाएं और इंटरफ़ेस घटक

वर्गों में गुण, स्थिरांक और विधियाँ हो सकती हैं।

  • गुण ऑब्जेक्ट के दायरे में चर रखते हैं। उन्हें घोषणा पर आरंभीकृत किया जा सकता है, लेकिन केवल अगर वे एक आदिम मूल्य रखते हैं।
  • स्थिरांक को घोषणा पर आरंभीकृत किया जाना चाहिए और इसमें केवल एक आदिम मूल्य हो सकता है। लगातार मूल्यों को संकलित समय पर निर्धारित किया जाता है और रन समय पर असाइन नहीं किया जा सकता है।
  • विधियों में एक शरीर होना चाहिए, यहां तक कि एक खाली भी, जब तक कि विधि को सार घोषित नहीं किया जाता है।
class Foo {
    private $foo = 'foo'; // OK
    private $baz = array(); // OK
    private $bar = new Bar(); // Error!
}

इंटरफेस में गुण नहीं हो सकते हैं, लेकिन स्थिरांक और विधियां हो सकती हैं।

  • इंटरफ़ेस स्थिरांक को घोषणा पर आरंभीकृत किया जाना चाहिए और इसमें केवल एक आदिम मान हो सकता है। लगातार मूल्यों को संकलित समय पर निर्धारित किया जाता है और रन समय पर असाइन नहीं किया जा सकता है।
  • इंटरफ़ेस के तरीकों में कोई शरीर नहीं है।
interface FooBar {
    const FOO_VALUE = 'bla';
    public function doAnything();
}

इंटरफेस

परिचय

इंटरफेस सार्वजनिक संतुष्ट करने के लिए इंटरफेस को लागू करने के लिए सार्वजनिक एपीआई वर्गों की परिभाषाएं हैं। वे "अनुबंध" के रूप में काम करते हैं, यह निर्दिष्ट करते हुए कि उपवर्गों का एक सेट क्या करता है, लेकिन नहीं कि वे इसे कैसे करते हैं।

इंटरफ़ेस की परिभाषा बहुत समान है वर्ग परिभाषा, कीवर्ड class को interface बदलना:

interface Foo {

}

इंटरफ़ेस में विधियाँ और / या स्थिरांक हो सकते हैं, लेकिन कोई विशेषता नहीं। इंटरफ़ेस स्थिरांक में कक्षा की स्थिरांक के समान प्रतिबंध हैं। इंटरफ़ेस तरीके संक्षेप में सार हैं:

interface Foo {
    const BAR = 'BAR';

    public function doSomething($param1, $param2);
}

नोट: इंटरफेस को कंस्ट्रक्टर या डिस्ट्रक्टर्स घोषित नहीं करना चाहिए , क्योंकि ये क्लास स्तर पर कार्यान्वयन विवरण हैं।

वसूली

किसी भी वर्ग को एक इंटरफ़ेस को लागू करने की आवश्यकता है जो कि implements कीवर्ड का उपयोग करके करना चाहिए। ऐसा करने के लिए, वर्ग को एक ही हस्ताक्षर का सम्मान करते हुए, इंटरफ़ेस में घोषित प्रत्येक विधि के लिए एक कार्यान्वयन प्रदान करना होगा।

एक एकल वर्ग एक समय में एक से अधिक इंटरफ़ेस लागू कर सकता है

interface Foo {
    public function doSomething($param1, $param2);
}

interface Bar {
    public function doAnotherThing($param1);
}


class Baz implements Foo, Bar {
    public function doSomething($param1, $param2) {
        // ...
    }

    public function doAnotherThing($param1) {
        // ...
    }
}

जब अमूर्त कक्षाएं इंटरफेस को लागू करती हैं, तो उन्हें सभी तरीकों को लागू करने की आवश्यकता नहीं होती है। बेस क्लास में लागू नहीं की गई किसी भी विधि को तब इसे लागू करने वाले ठोस वर्ग द्वारा लागू किया जाना चाहिए:

abstract class AbstractBaz implements Foo, Bar {
    // Partial implementation of the required interface...
    public function doSomething($param1, $param2) {
        // ...
    }
}

class Baz extends AbstractBaz {
    public function doAnotherThing($param1) {
        // ...
    }
}

ध्यान दें कि इंटरफ़ेस अहसास एक विरासत में मिली विशेषता है। जब एक वर्ग का विस्तार होता है जो एक इंटरफ़ेस को लागू करता है, तो आपको इसे ठोस वर्ग में फिर से विभाजित करने की आवश्यकता नहीं है, क्योंकि यह निहित है।

नोट: PHP 5.3.9 से पहले, एक वर्ग दो इंटरफेस को लागू नहीं कर सकता था जो एक ही नाम के साथ एक विधि निर्दिष्ट करते थे, क्योंकि यह अस्पष्टता का कारण होगा। PHP के अधिक हाल के संस्करणों के रूप में लंबे समय के रूप में डुप्लिकेट तरीकों में एक ही हस्ताक्षर [1] है

विरासत

वर्गों की तरह, यह संभव इंटरफेस के बीच एक विरासत संबंध स्थापित करने, का उपयोग करते हुए एक ही कीवर्ड है extends । मुख्य अंतर यह है कि इंटरफेस के लिए कई विरासत की अनुमति है:

interface Foo {

}

interface Bar {

}

interface Baz extends Foo, Bar {

}

उदाहरण

उदाहरण बलो में हमारे पास एक वाहन के लिए एक सरल उदाहरण इंटरफ़ेस है। वाहन आगे और पीछे जा सकते हैं।

interface VehicleInterface {
    public function forward();

    public function reverse();

    ...
}

class Bike implements VehicleInterface {
    public function forward() {
        $this->pedal();
    }

    public function reverse() {
        $this->backwardSteps();
    }

    protected function pedal() {
        ...
    }

    protected function backwardSteps() {
        ...
    }

    ...
}

class Car implements VehicleInterface {
    protected $gear = 'N';

    public function forward() {
        $this->setGear(1);
        $this->pushPedal();
    }

    public function reverse() {
        $this->setGear('R');
        $this->pushPedal();
    }

    protected function setGear($gear) {
        $this->gear = $gear;
    }

    protected function pushPedal() {
        ...
    }

    ...
}

फिर हम दो कक्षाएं बनाते हैं जो इंटरफ़ेस को लागू करते हैं: बाइक और कार। बाइक और कार आंतरिक रूप से बहुत अलग हैं, लेकिन दोनों ही वाहन हैं, और उन्हीं सार्वजनिक तरीकों को लागू करना चाहिए जो वाहनइंटरफेस प्रदान करता है।

टाइपिंग इंटरफेसेस का अनुरोध करने के तरीकों और कार्यों की अनुमति देता है। मान लेते हैं कि हमारे पास एक पार्किंग गैरेज क्लास है, जिसमें सभी प्रकार के वाहन हैं।

class ParkingGarage {
    protected $vehicles = [];

    public function addVehicle(VehicleInterface $vehicle) {
        $this->vehicles[] = $vehicle;
    }
}

क्योंकि addVehicle को एक $vehicle के प्रकार की आवश्यकता होती है VehicleInterface ठोस कार्यान्वयन नहीं - हम दोनों Bike और Cars को इनपुट कर सकते हैं, जिसे ParkingGarage हेरफेर और उपयोग कर सकता है।

क्लास कांस्टेंट

क्लास कॉन्स्टेंट एक प्रोग्राम में निश्चित मान रखने के लिए एक तंत्र प्रदान करते हैं। यही है, वे 3.14 या "Apple" जैसे मूल्य के लिए एक नाम (और संबंधित संकलन-समय की जाँच) देने का एक तरीका प्रदान करते हैं। क्लास कांस्टेंट को केवल const कीवर्ड के साथ परिभाषित किया जा सकता है - परिभाषित फ़ंक्शन का उपयोग इस संदर्भ में नहीं किया जा सकता है।

एक उदाहरण के रूप में, पूरे कार्यक्रम में a के मूल्य के लिए शॉर्टहैंड प्रतिनिधित्व करना सुविधाजनक हो सकता है। const वैल्यूज वाला एक क्लास ऐसे मूल्यों को रखने का एक सरल तरीका प्रदान करता है।

class MathValues {
    const PI = M_PI;
    const PHI = 1.61803;
}

$area = MathValues::PI * $radius * $radius;

क्लास कॉन्स्टेंट को डबल कोलन ऑपरेटर (तथाकथित स्कोप रिज़ॉल्यूशन ऑपरेटर) का उपयोग करके एक क्लास पर पहुँचा जा सकता है, जो स्टैटिक वैरिएबल की तरह है। हालांकि, स्थिर चर के विपरीत, वर्ग स्थिरांक का अपना मान संकलन समय पर निर्धारित होता है और इसे पुन: असाइन नहीं किया जा सकता है (जैसे MathValues::PI = 7 एक घातक त्रुटि पैदा करेगा)।

एक कक्षा में आंतरिक चीजों को परिभाषित करने के लिए कक्षा स्थिरांक भी उपयोगी होते हैं, जिन्हें बाद में बदलने की आवश्यकता हो सकती है (लेकिन, डेटाबेस कहते हैं, वारंट भंडारण के लिए अक्सर पर्याप्त नहीं बदलते हैं)। हम इसे आंतरिक रूप से self स्कोप रेसोल्यूटर (जो इंस्टेंट और स्टैटिक इंप्लीमेंट दोनों में काम करता है) का उपयोग करके संदर्भित कर सकते हैं

class Labor {
    /** How long, in hours, does it take to build the item? */
    const LABOR_UNITS = 0.26;
    /** How much are we paying employees per hour? */
    const LABOR_COST = 12.75;

    public function getLaborCost($number_units) {
         return (self::LABOR_UNITS * self::LABOR_COST) * $number_units;
    }
}

वर्ग स्थिरांक केवल संस्करणों में स्केलर मान शामिल कर सकते हैं <5.6

PHP 5.6 के रूप में हम स्थिरांक के साथ भावों का उपयोग कर सकते हैं, जिसका अर्थ है गणित कथन और संघनन के साथ तार स्वीकार्य स्थिरांक हैं

class Labor {
    /** How much are we paying employees per hour? Hourly wages * hours taken to make */
    const LABOR_COSTS = 12.75 * 0.26;

    public function getLaborCost($number_units) {
         return self::LABOR_COSTS * $number_units;
    }
}

PHP 7.0 के अनुसार, define स्थिरांक में अब सरणियाँ हो सकती हैं।

define("BAZ", array('baz'));

कक्षा की अवधारणाएं गणितीय अवधारणाओं को संग्रहीत करने से अधिक के लिए उपयोगी हैं। उदाहरण के लिए, यदि पाई तैयार करते हैं, तो एक ही Pie वर्ग के लिए विभिन्न प्रकार के फल लेने में सक्षम होना सुविधाजनक हो सकता है।

class Pie {
    protected $fruit;

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

हम तब Pie वर्ग का उपयोग कर सकते हैं

$pie = new Pie("strawberry");

यहां जो समस्या उत्पन्न होती है, वह है जब Pie क्लास को Pie करना, स्वीकार्य मानों के अनुसार कोई मार्गदर्शन प्रदान नहीं किया जाता है। उदाहरण के लिए, "बॉयसेनबेरी" पाई बनाते समय, इसे "बोइसेबेरी" कहा जा सकता है। इसके अलावा, हम बेर पाई का समर्थन नहीं कर सकते हैं। इसके बजाय, यह स्वीकार्य फलों के प्रकारों की एक सूची के लिए उपयोगी होगा जो पहले से ही कहीं न कहीं परिभाषित है जो उनके लिए देखने के लिए समझ में आता है। Fruit नामक एक वर्ग कहें:

class Fruit {
    const APPLE = "apple";
    const STRAWBERRY = "strawberry";
    const BOYSENBERRY = "boysenberry";
}

$pie = new Pie(Fruit::STRAWBERRY);

स्वीकार्य मानों को वर्ग स्थिरांक के रूप में सूचीबद्ध करना एक मूल्यवान संकेत प्रदान करता है, जो स्वीकार्य मानों को स्वीकार करता है, जिसे एक विधि स्वीकार करती है। यह यह भी सुनिश्चित करता है कि प्रक्षेपास्त्र इसे संकलक से अतीत नहीं बना सकते। जबकि new Pie('aple') और new Pie('apple') दोनों संकलक के लिए स्वीकार्य हैं, new Pie(Fruit::APLE) एक संकलक त्रुटि का उत्पादन करेंगे।

अंत में, वर्ग स्थिरांक का उपयोग करने का अर्थ है कि निरंतर का वास्तविक मूल्य एक ही स्थान पर संशोधित किया जा सकता है, और निरंतर उपयोग करने वाले किसी भी कोड में संशोधन का प्रभाव होता है।

जब तक किसी वर्ग की निरंतरता प्राप्त करने के लिए सबसे आम तरीका MyClass::CONSTANT_NAME , तब तक इसे भी एक्सेस किया जा सकता है:

echo MyClass::CONSTANT;

$classname = "MyClass";
echo $classname::CONSTANT; // As of PHP 5.3.0

PHP में वर्ग स्थिरांक को पारंपरिक रूप से अपरकेस के साथ सभी में शब्द विभाजक के रूप में नामित किया जाता है, हालांकि किसी भी मान्य लेबल नाम का उपयोग कक्षा निरंतर नाम के रूप में किया जा सकता है।

PHP 7.1 के रूप में, क्लास कॉन्स्टेंट को अब डिफ़ॉल्ट पब्लिक स्कोप से अलग-अलग विज़िबिलिटी के साथ परिभाषित किया जा सकता है। इसका मतलब यह है कि संरक्षित और निजी स्थिरांक दोनों को अब सार्वजनिक रूप से अनावश्यक रूप से लीक होने से रोकने के लिए परिभाषित किया जा सकता है ( विधि और संपत्ति दृश्यता देखें )। उदाहरण के लिए:

class Something {
    const PUBLIC_CONST_A = 1;
    public const PUBLIC_CONST_B = 2;
    protected const PROTECTED_CONST = 3;
    private const PRIVATE_CONST = 4;
}

बनाम वर्ग की निरंतरता

हालांकि यह एक वैध निर्माण है:

function bar() { return 2; };

define('BAR', bar());

यदि आप कक्षा में स्थिरांक के साथ ऐसा करने का प्रयास करते हैं, तो आपको एक त्रुटि मिलेगी:

function bar() { return 2; };

class Foo {
    const BAR = bar(); // Error: Constant expression contains invalid operations
}

लेकिन आप कर सकते हैं:

function bar() { return 2; };

define('BAR', bar());

class Foo {
    const BAR = BAR; // OK
}

अधिक जानकारी के लिए, मैनुअल में स्थिरांक देखें।

कक्षा के नाम को पुनः प्राप्त करने के लिए :: वर्ग का उपयोग करना

PHP 5.5 ने ::class सिंटैक्स को पूर्ण श्रेणी के नाम को पुनः प्राप्त करने के लिए पेश किया, नेमस्पेस स्कोप लिया और विवरणों का use किया।

namespace foo;
use bar\Bar;
echo json_encode(Bar::class); // "bar\\Bar"
echo json_encode(Foo::class); // "foo\\Foo"
echo json_encode(\Foo::class); // "Foo"

उपरोक्त कार्य तब भी करते हैं जब कक्षाएं भी परिभाषित नहीं होती हैं (अर्थात यह कोड स्निपेट अकेले काम करता है)।

यह सिंटैक्स उन कार्यों के लिए उपयोगी है जिनके लिए एक वर्ग नाम की आवश्यकता होती है। उदाहरण के लिए, यह एक वर्ग की जाँच करने के लिए class_exists साथ प्रयोग किया जा सकता है। इस स्निपेट में वापसी मूल्य की परवाह किए बिना कोई त्रुटि उत्पन्न नहीं होगी:

class_exists(ThisClass\Will\NeverBe\Loaded::class, false);

देर से स्थिर बंधन

PHP 5.3+ और उससे अधिक में आप यह नियंत्रित करने के लिए देर से स्थैतिक बंधन का उपयोग कर सकते हैं कि किस वर्ग से एक स्थिर संपत्ति या विधि को कहा जाता है। यह self:: गुंजाइश संकल्प के साथ निहित समस्या को दूर करने के लिए जोड़ा गया था। निम्नलिखित कोड लें

class Horse {
    public static function whatToSay() {
         echo 'Neigh!';
    }

    public static function speak() {
         self::whatToSay();
    }
}

class MrEd extends Horse {
    public static function whatToSay() {
         echo 'Hello Wilbur!';
    }
}

आप उम्मीद करेंगे कि MrEd वर्ग पैरेंट whatToSay() फ़ंक्शन को ओवरराइड करेगा। लेकिन जब हम इसे चलाते हैं तो हमें कुछ अप्रत्याशित मिलता है

Horse::speak(); // Neigh!
MrEd::speak(); // Neigh!

समस्या यह है कि self::whatToSay(); केवल Horse क्लास को संदर्भित कर सकते हैं, जिसका अर्थ है कि यह MrEd पालन नहीं करता है। अगर हम static:: स्कोप रेसोलुटर पर स्विच करते हैं, तो हमें यह समस्या नहीं है। यह नया तरीका कक्षा को यह कहता है कि उसे कॉल करने वाले उदाहरण का पालन करना चाहिए। इस प्रकार हमें वह उत्तराधिकार प्राप्त होता है जिसकी हम अपेक्षा करते हैं

class Horse {
    public static function whatToSay() {
         echo 'Neigh!';
    }

    public static function speak() {
         static::whatToSay(); // Late Static Binding
    }
}

Horse::speak(); // Neigh!
MrEd::speak(); // Hello Wilbur!

सार वर्ग

एक अमूर्त वर्ग एक ऐसा वर्ग है जिसे त्वरित नहीं किया जा सकता है। अमूर्त कक्षाएं अमूर्त विधियों को परिभाषित कर सकती हैं, जो बिना किसी निकाय के विधियां हैं, केवल एक परिभाषा:

abstract class MyAbstractClass {
    abstract public function doSomething($a, $b);
}

एब्सट्रैक्ट क्लासेस को एक चाइल्ड क्लास द्वारा बढ़ाया जाना चाहिए जो तब इन अमूर्त विधियों के कार्यान्वयन को प्रदान कर सकता है।

इस तरह की एक कक्षा का मुख्य उद्देश्य एक प्रकार का टेम्पलेट प्रदान करना है जो बच्चों की कक्षाओं को "पालन" के लिए एक संरचना का पालन करने की अनुमति देता है। एक उदाहरण के साथ इस पर विस्तार से दें:

इस उदाहरण में हम एक Worker इंटरफ़ेस लागू करेंगे। पहले हम इंटरफ़ेस को परिभाषित करते हैं:

interface Worker {
    public function run();
}

आगे के कार्यकर्ता कार्यान्वयन के विकास को आसान बनाने के लिए, हम एक एब्सट्रैक्ट वर्कर क्लास बनाएंगे जो पहले से ही इंटरफ़ेस से run() विधि प्रदान करता है, लेकिन कुछ सार तरीके निर्दिष्ट करता है जिन्हें किसी भी चाइल्ड क्लास द्वारा भरने की आवश्यकता होती है:

abstract class AbstractWorker implements Worker {
    protected $pdo;
    protected $logger;

    public function __construct(PDO $pdo, Logger $logger) {
        $this->pdo = $pdo;
        $this->logger = $logger;
    }

    public function run() {
        try {
            $this->setMemoryLimit($this->getMemoryLimit());
            $this->logger->log("Preparing main");
            $this->prepareMain();
            $this->logger->log("Executing main");
            $this->main();
        } catch (Throwable $e) {
            // Catch and rethrow all errors so they can be logged by the worker
            $this->logger->log("Worker failed with exception: {$e->getMessage()}");
            throw $e;
        }
    }

    private function setMemoryLimit($memoryLimit) {
        ini_set('memory_limit', $memoryLimit);
        $this->logger->log("Set memory limit to $memoryLimit");
    }

    abstract protected function getMemoryLimit();

    abstract protected function prepareMain();

    abstract protected function main();
}

सबसे पहले, हमने एक अमूर्त विधि getMemoryLimit()AbstractWorker से विस्तार करने वाले किसी भी वर्ग को यह विधि प्रदान करने और अपनी स्मृति सीमा वापस करने की आवश्यकता है। AbstractWorker फिर मेमोरी लिमिट सेट करता है और उसे लॉग करता है।

दूसरी बात यह है कि AbstractWorker prepareMain() और main() विधियों को कॉल करता है, लॉगिंग के बाद कि उन्हें बुलाया गया है।

अंत में, इन विधि कॉल के सभी एक में वर्गीकृत किया गया है try - catch ब्लॉक। इसलिए यदि चाइल्ड क्लास द्वारा परिभाषित कोई भी सार पद्धति एक अपवाद को फेंक देती है, तो हम उस अपवाद को पकड़ लेंगे, उसे लॉग इन करेंगे और उसे रीथ्रो कर देंगे। यह सभी बाल वर्गों को स्वयं इसे लागू करने से रोकता है।

अब एक बाल वर्ग को परिभाषित करता है जो AbstractWorker से AbstractWorker :

class TranscactionProcessorWorker extends AbstractWorker {
    private $transactions;

    protected function getMemoryLimit() {
        return "512M";
    }

    protected function prepareMain() {
        $stmt = $this->pdo->query("SELECT * FROM transactions WHERE processed = 0 LIMIT 500");
        $stmt->execute();
        $this->transactions = $stmt->fetchAll();
    }

    protected function main() {
        foreach ($this->transactions as $transaction) {
            // Could throw some PDO or MYSQL exception, but that is handled by the AbstractWorker
            $stmt = $this->pdo->query("UPDATE transactions SET processed = 1 WHERE id = {$transaction['id']} LIMIT 1");
            $stmt->execute();
        }
    }
}

जैसा कि आप देख सकते हैं, TransactionProcessorWorker को लागू करना आसान था, क्योंकि हमें केवल मेमोरी सीमा को निर्दिष्ट करना था और वास्तविक क्रियाओं के बारे में चिंता करना था जो इसे करने की आवश्यकता थी। TransactionProcessorWorker में कोई त्रुटि हैंडलिंग की आवश्यकता नहीं है क्योंकि यह AbsractWorker में संभाला जाता है।

महत्वपूर्ण लेख

जब एक अमूर्त वर्ग से विरासत में मिला है, तो माता-पिता की कक्षा घोषणा में अमूर्त के रूप में चिह्नित सभी तरीकों को बच्चे द्वारा परिभाषित किया जाना चाहिए (या बच्चे को खुद को भी सार होना चाहिए); इसके अतिरिक्त, इन विधियों को समान (या कम प्रतिबंधित) दृश्यता के साथ परिभाषित किया जाना चाहिए। उदाहरण के लिए, यदि सार पद्धति को संरक्षित के रूप में परिभाषित किया गया है, तो फ़ंक्शन कार्यान्वयन को संरक्षित या सार्वजनिक रूप से परिभाषित किया जाना चाहिए, लेकिन निजी नहीं।

क्लास एब्स्ट्रक्शन के लिए PHP डॉक्यूमेंटेशन से लिया गया।

यदि आप चाइल्ड क्लास के भीतर पैरेंट एब्स्ट्रैक्ट क्लासेस के तरीकों को परिभाषित नहीं करते हैं, तो आपको निम्नलिखित की तरह एक घातक PHP त्रुटि दी जाएगी।

घातक त्रुटि: दसवीं कक्षा में 1 सार पद्धति होती है और इसलिए उसे सार घोषित किया जाना चाहिए या शेष विधियों (X :: x) को लागू करना चाहिए

नेमस्पेसिंग और ऑटोलडिंग

तकनीकी रूप से, ऑटोलैडिंग एक कॉलबैक निष्पादित करके काम करता है जब PHP वर्ग की आवश्यकता होती है लेकिन नहीं मिलती है। ऐसे कॉलबैक आमतौर पर इन कक्षाओं को लोड करने का प्रयास करते हैं।

आमतौर पर, ऑटोलॉडिंग को PHP फ़ाइलों (विशेष रूप से PHP क्लास फाइलें, जहां एक वर्ग के लिए एक विशिष्ट वर्ग के लिए एक PHP स्रोत फ़ाइल समर्पित है) को कक्षा के पूरी तरह से योग्य नाम (FQN) के अनुसार लोड करने के प्रयास के रूप में समझा जा सकता है जब एक वर्ग की आवश्यकता होती है ।

मान लीजिए कि हमारे पास ये कक्षाएं हैं:

application\controllers\Base लिए वर्ग फ़ाइल:

<?php
namespace application\controllers { class Base {...} }

application\controllers\Control लिए कक्षा फ़ाइल:

<?php
namespace application\controllers { class Control {...} }

application\models\Page लिए कक्षा फ़ाइल:

<?php
namespace application\models { class Page {...} }

स्रोत फ़ोल्डर के तहत, इन वर्गों को क्रमशः FQN के रूप में पथों पर रखा जाना चाहिए:

  • सोर्स फोल्डर
    • applications
      • controllers
        • Base.php
        • Control.php
      • models
        • Page.php

यह दृष्टिकोण इस फ़ंक्शन का उपयोग करके FQN के अनुसार प्रोग्राम फ़ाइल पथ को प्रोग्रामेटिक रूप से हल करना संभव बनाता है:

function getClassPath(string $sourceFolder, string $className, string $extension = ".php") {
    return $sourceFolder . "/" . str_replace("\\", "/", $className) . $extension; // note that "/" works as a directory separator even on Windows
}

spl_autoload_register फ़ंक्शन उपयोगकर्ता-निर्धारित फ़ंक्शन का उपयोग करके हमें एक वर्ग लोड करने की अनुमति देता है:

const SOURCE_FOLDER = __DIR__ . "/src";
spl_autoload_register(function (string $className) {
    $file = getClassPath(SOURCE_FOLDER, $className);
    if (is_readable($file)) require_once $file;
});

इस फ़ंक्शन को लोडिंग के फ़ालबैक तरीकों का उपयोग करने के लिए आगे बढ़ाया जा सकता है:

const SOURCE_FOLDERS = [__DIR__ . "/src", "/root/src"]);
spl_autoload_register(function (string $className) {
    foreach(SOURCE_FOLDERS as $folder) {
        $extensions = [
            // do we have src/Foo/Bar.php5_int64?
            ".php" . PHP_MAJOR_VERSION . "_int" . (PHP_INT_SIZE * 8),
            // do we have src/Foo/Bar.php7?
            ".php" . PHP_MAJOR_VERSION,
            // do we have src/Foo/Bar.php_int64?
            ".php" . "_int" . (PHP_INT_SIZE * 8),
            // do we have src/Foo/Bar.phps?
            ".phps"
            // do we have src/Foo/Bar.php?
            ".php"
        ];
        foreach($extensions as $ext) {
            $path = getClassPath($folder, $className, $extension);
            if(is_readable($path)) return $path;
        }
    }
});

ध्यान दें कि PHP जब भी इस वर्ग का उपयोग करने वाली फ़ाइल लोड होती है, तो कक्षाओं को लोड करने का प्रयास नहीं करती है। इसे स्क्रिप्ट के बीच में, या शटडाउन फ़ंक्शन में भी लोड किया जा सकता है। यह एक कारण है कि डेवलपर्स, विशेष रूप से जो ऑटोलडिंग का उपयोग करते हैं, उन्हें रनटाइम में स्रोत फ़ाइलों को निष्पादित करने से बचना चाहिए, विशेष रूप से फ़ार फ़ाइलों में।

गतिशील बंधन

डायनेमिक बाइंडिंग, जिसे मेथड ओवरराइडिंग भी कहा जाता है, रन टाइम पॉलिमॉर्फिज़्म का एक उदाहरण है जो तब होता है जब कई वर्गों में एक ही विधि के अलग-अलग कार्यान्वयन होते हैं, लेकिन जिस विधि को कॉल किया जाएगा वह रन टाइम तक अज्ञात है

यह उपयोगी है यदि एक निश्चित स्थिति तय करती है कि किस वर्ग का उपयोग कार्रवाई करने के लिए किया जाएगा, जहां कार्रवाई को दोनों वर्गों में समान नाम दिया गया है।

interface Animal {
    public function makeNoise();
}

class Cat implements Animal {
    public function makeNoise
    {
        $this->meow();
    }
    ...
}

class Dog implements Animal {
    public function makeNoise {
        $this->bark();
    }
    ...
}

class Person {
    const CAT = 'cat';
    const DOG = 'dog';

    private $petPreference;
    private $pet;

    public function isCatLover(): bool {
        return $this->petPreference == self::CAT;
    }

    public function isDogLover(): bool {
        return $this->petPreference == self::DOG;
    }

    public function setPet(Animal $pet) {
        $this->pet = $pet;
    }

    public function getPet(): Animal {
        return $this->pet;
    }
}

if($person->isCatLover()) {
    $person->setPet(new Cat());
} else if($person->isDogLover()) {
    $person->setPet(new Dog());
}

$person->getPet()->makeNoise();

उपर्युक्त उदाहरण में, Animal क्लास ( Dog|Cat ) जो makeNoise करेगा, वह अज्ञात है जब तक कि User वर्ग के भीतर संपत्ति पर निर्भर करता है।

विधि और संपत्ति दृश्यता

तीन दृश्यता प्रकार हैं जो आप एक वर्ग के भीतर तरीकों ( वर्ग / वस्तु कार्यों ) और गुणों ( वर्ग / वस्तु चर ) पर लागू कर सकते हैं, जो उस पद्धति या संपत्ति के लिए पहुंच नियंत्रण प्रदान करते हैं जिस पर वे लागू होते हैं।

OOP विजिबिलिटी के लिए PHP डॉक्यूमेंटेशन में आप इनके बारे में विस्तार से पढ़ सकते हैं।

जनता

विधि या संपत्ति को public घोषित करने से विधि या संपत्ति को एक्सेस करने की अनुमति मिलती है:

  • जिस वर्ग ने इसे घोषित किया।
  • वे वर्ग जो घोषित वर्ग का विस्तार करते हैं।
  • वर्ग पदानुक्रम के बाहर कोई भी बाहरी वस्तु, वर्ग या कोड।

इस public पहुंच का एक उदाहरण होगा:

class MyClass {
    // Property
    public $myProperty = 'test';

    // Method
    public function myMethod() {
        return $this->myProperty;
    }
}

$obj = new MyClass();
echo $obj->myMethod();
// Out: test

echo $obj->myProperty;
// Out: test

संरक्षित

एक विधि या संपत्ति की घोषणा के रूप में protected विधि या संपत्ति द्वारा पहुँचा जा सकता है:

  • जिस वर्ग ने इसे घोषित किया।
  • वे वर्ग जो घोषित वर्ग का विस्तार करते हैं।

यह बाहरी वस्तुओं, वर्गों, या वर्ग पदानुक्रम के बाहर कोड को इन विधियों या गुणों तक पहुंचने की अनुमति नहीं देता है । यदि इस पद्धति / संपत्ति का उपयोग करने वाली किसी चीज तक इसकी पहुंच नहीं है, तो यह उपलब्ध नहीं होगी, और एक त्रुटि डाली जाएगी। घोषित स्व (या उपवर्ग) के केवल उदाहरणों तक इसकी पहुँच है।

इस protected पहुंच का एक उदाहरण होगा:

class MyClass {
    protected $myProperty = 'test';

    protected function myMethod() {
        return $this->myProperty;
    }
}

class MySubClass extends MyClass {
    public function run() {
        echo $this->myMethod();
    }
}

$obj = new MySubClass();
$obj->run(); // This will call MyClass::myMethod();
// Out: test

$obj->myMethod(); // This will fail.
// Out: Fatal error: Call to protected method MyClass::myMethod() from context ''

ऊपर दिए गए उदाहरणों से पता चलता है कि आप केवल protected तत्वों को ही अपने दायरे में ले सकते हैं। अनिवार्य रूप से: "घर में क्या है केवल घर के अंदर से ही पहुँचा जा सकता है।"


निजी

एक विधि या संपत्ति को private घोषित करना विधि या संपत्ति को उसके द्वारा एक्सेस करने की अनुमति देता है:

  • वर्ग जिसने इसे घोषित किया ( केवल उपवर्ग नहीं)।

एक private पद्धति या संपत्ति केवल उस वर्ग के भीतर दिखाई और पहुंच योग्य है जिसने इसे बनाया है।

ध्यान दें कि एक ही प्रकार की वस्तुओं की एक-दूसरे से निजी और संरक्षित सदस्यों तक पहुंच होगी, भले ही वे एक ही उदाहरण न हों।

class MyClass {
    private $myProperty = 'test';

    private function myPrivateMethod() {
        return $this->myProperty;
    }

    public function myPublicMethod() {
        return $this->myPrivateMethod();
    }

    public function modifyPrivatePropertyOf(MyClass $anotherInstance) {
        $anotherInstance->myProperty = "new value";
    }
}

class MySubClass extends MyClass {
    public function run() {
        echo $this->myPublicMethod();
    }

    public function runWithPrivate() {
        echo $this->myPrivateMethod();
    }
}

$obj = new MySubClass();
$newObj = new MySubClass();

// This will call MyClass::myPublicMethod(), which will then call
// MyClass::myPrivateMethod();
$obj->run(); 
// Out: test

    
$obj->modifyPrivatePropertyOf($newObj);

$newObj->run();
// Out: new value

echo $obj->myPrivateMethod(); // This will fail.
// Out: Fatal error: Call to private method MyClass::myPrivateMethod() from context ''

echo $obj->runWithPrivate(); // This will also fail.
// Out: Fatal error: Call to private method MyClass::myPrivateMethod() from context 'MySubClass'

जैसा कि कहा गया है, आप केवल private पद्धति / संपत्ति को ही परिभाषित वर्ग के भीतर से एक्सेस कर सकते हैं।

बच्चे को इंस्टेंट करते समय पैरेंट कंस्ट्रक्टर को कॉल करना

बाल वर्गों का एक सामान्य नुकसान यह है कि, यदि आपके माता-पिता और बच्चे दोनों के पास एक कंस्ट्रक्टर ( __construct() ) विधि है, तो केवल चाइल्ड क्लास कंस्ट्रक्टर चलेगा । ऐसे मौके हो सकते हैं जहां आपको बच्चे से माता-पिता की __construct() विधि को चलाने की आवश्यकता हो। यदि आपको ऐसा करने की आवश्यकता है, तो आपको parent:: का उपयोग करने की आवश्यकता होगी parent:: गुंजाइश संकल्प:

parent::__construct();

अब यह कहना कि वास्तविक दुनिया की स्थिति कुछ इस तरह होगी:

class Foo {

    function __construct($args) { 
        echo 'parent'; 
    }

}

class Bar extends Foo {

    function __construct($args) {
        parent::__construct($args);
    }
}

ऊपर अभिभावक __construct() चलाएगा जिसके परिणामस्वरूप echo चल रही है।

अंतिम खोजशब्द

Def: अंतिम कीवर्ड बाल वर्गों को अंतिम के साथ परिभाषा को उपसर्ग करके एक विधि को ओवरराइड करने से रोकता है। यदि वर्ग को ही अंतिम रूप से परिभाषित किया जा रहा है तो इसे बढ़ाया नहीं जा सकता है

अंतिम विधि

class BaseClass {
   public function test() {
       echo "BaseClass::test() called\n";
   }
   
   final public function moreTesting() {
       echo "BaseClass::moreTesting() called\n";
   }
}

class ChildClass extends BaseClass {
   public function moreTesting() {
       echo "ChildClass::moreTesting() called\n";
   }
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()

अंतिम वर्ग:

final class BaseClass {
   public function test() {
       echo "BaseClass::test() called\n";
   }

   // Here it doesn't matter if you specify the function as final or not
   final public function moreTesting() {
       echo "BaseClass::moreTesting() called\n";
   }
}

class ChildClass extends BaseClass {
}
// Results in Fatal error: Class ChildClass may not inherit from final class (BaseClass)

अंतिम स्थिरांक: जावा के विपरीत, final खोजशब्द PHP में वर्ग स्थिरांक के लिए उपयोग नहीं किया जाता है। इसके बजाय कीवर्ड const उपयोग करें।

मुझे final उपयोग क्यों करना है?

  1. कयामत की व्यापक विरासत श्रृंखला को रोकना
  2. रचना को प्रोत्साहित करना
  3. उपयोगकर्ता सार्वजनिक API के बारे में सोचने के लिए डेवलपर को बाध्य करें
  4. किसी ऑब्जेक्ट के सार्वजनिक API को छोटा करने के लिए डेवलपर को बाध्य करें
  5. एक final वर्ग हमेशा एक्स्टेंसिबल बनाया जा सकता है
  6. extends टूटना
  7. आपको उस लचीलेपन की आवश्यकता नहीं है
  8. आप कोड बदलने के लिए स्वतंत्र हैं

final से बचने के लिए: अंतिम कक्षाएं केवल निम्नलिखित मान्यताओं के तहत प्रभावी रूप से काम करती हैं:

  1. एक अमूर्त (इंटरफ़ेस) है जो अंतिम वर्ग को लागू करता है
  2. अंतिम वर्ग के सभी सार्वजनिक एपीआई उस इंटरफ़ेस का हिस्सा हैं

$ यह, स्व और स्थैतिक प्लस सिंगलटन

वर्तमान वस्तु को संदर्भित करने के लिए $this उपयोग करें। वर्तमान वर्ग को संदर्भित करने के लिए self का उपयोग करें। दूसरे शब्दों में, गैर-स्थैतिक सदस्यों के लिए $this->member उपयोग $this->member स्थैतिक सदस्यों के लिए self::$member उपयोग करें।

नीचे दिए गए उदाहरण में, sayHello() और sayGoodbye() self का उपयोग कर रहे हैं और $this अंतर को यहां देखा जा सकता है।

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();

static तात्पर्य है कि पदानुक्रम में आप जिस भी विधि को कहते हैं, उस वर्ग को। जब क्लास विरासत में मिलती हैं तो यह स्थिर वर्ग गुणों के बेहतर पुन: उपयोग की अनुमति देता है।

निम्नलिखित कोड पर विचार करें:

class Car {
    protected static $brand = 'unknown';
    
    public static function brand() {
         return self::$brand."\n";
    }
}

class Mercedes extends Car {
    protected static $brand = 'Mercedes';
}

class BMW extends Car {
    protected static $brand = 'BMW';
}

echo (new Car)->brand();
echo (new BMW)->brand();
echo (new Mercedes)->brand();

यह आपके इच्छित परिणाम का उत्पादन नहीं करता है:

अनजान
अनजान
अनजान

ऐसा इसलिए है क्योंकि जब भी विधि brand() कहा जाता है तो self Car वर्ग को संदर्भित करता है।

सही वर्ग को संदर्भित करने के लिए, आपको इसके बजाय static का उपयोग करने की आवश्यकता है:

class Car {
    protected static $brand = 'unknown';
    
    public static function brand() {
         return static::$brand."\n";
    }
}

class Mercedes extends Car {
    protected static $brand = 'Mercedes';
}

class BMW extends Car {
    protected static $brand = 'BMW';
}

echo (new Car)->brand();
echo (new BMW)->brand();
echo (new Mercedes)->brand();

यह वांछित उत्पादन का उत्पादन करता है:

अनजान
बीएमडब्ल्यू
मर्सिडीज

लेट स्टैटिक बाइंडिंग भी देखें

एकटा गाछ

यदि आपके पास कोई ऐसी वस्तु है जो आपके द्वारा उपयोग किए जाने वाले किसी बाहरी संसाधन से संबंध बनाने या उसका प्रतिनिधित्व करने के लिए महंगी है, तो एक डेटाबेस कनेक्शन जहां कोई कनेक्शन पूलिंग या किसी अन्य सिस्टम के लिए सॉकेट नहीं है, आप static और self कीवर्ड का उपयोग कर सकते हैं वर्ग इसे एक एकल बनाने के लिए। इस बारे में मजबूत राय है कि सिंगलटन पैटर्न का उपयोग किया जाना चाहिए या नहीं, लेकिन इसके उपयोग हैं।

class Singleton {
    private static $instance = null;

    public static function getInstance(){
        if(!isset(self::$instance)){
            self::$instance = new self();
        }
        
        return self::$instance;
    }
    
    private function __construct() {
        // Do constructor stuff
    }
}

जैसा कि आप उदाहरण कोड में देख सकते हैं कि हम एक निजी स्टेटिक प्रॉपर्टी $instance को ऑब्जेक्ट संदर्भ रखने के $instance परिभाषित कर रहे हैं। चूंकि यह स्थिर है इसलिए यह संदर्भ इस प्रकार की सभी वस्तुओं में साझा किया गया है।

getInstance() विधि अंतिम संभव क्षण तक ऑब्जेक्ट बनाने में देरी करने के लिए आलसी इंस्ट्रूमेंटेशन के रूप में getInstance() एक विधि का उपयोग करती है क्योंकि आप नहीं चाहते कि स्मृति में आस-पास पड़ी अप्रयुक्त वस्तुएं कभी भी उपयोग करने का इरादा न करें। यह पृष्ठ लोड पर समय और सीपीयू भी बचाता है और आवश्यकता से अधिक वस्तुओं को लोड करने के लिए नहीं है। विधि जाँच रही है कि क्या ऑब्जेक्ट सेट है, यदि नहीं, तो इसे बनाए और वापस लौटाए। यह सुनिश्चित करता है कि इस तरह की केवल एक वस्तु कभी बनाई जाती है।

हम यह सुनिश्चित करने के लिए निर्माणकर्ता को भी निजी बना रहे हैं कि कोई भी इसे बाहर से new कीवर्ड के साथ न बनाए। यदि आपको इस वर्ग से विरासत में प्राप्त करने की आवश्यकता है तो protected करने के लिए private कीवर्ड बदलें।

इस ऑब्जेक्ट का उपयोग करने के लिए आप बस निम्नलिखित लिखें:

$singleton = Singleton::getInstance();

अब मैं आपको निर्भरता इंजेक्शन का उपयोग करने के लिए निहित करता हूं जहां आप शिथिल युग्मित वस्तुओं के लिए कर सकते हैं और लक्ष्य कर सकते हैं, लेकिन कभी-कभी यह उचित नहीं है और सिंगलटन पैटर्न का उपयोग किया जा सकता है।

autoloading

कोई नहीं चाहता है require या include हर बार कक्षा या विरासत प्रयोग किया जाता है। क्योंकि यह दर्दनाक हो सकता है और भूलना आसान है, PHP तथाकथित ऑटोलिडिंग की पेशकश कर रहा है। यदि आप पहले से ही संगीतकार का उपयोग कर रहे हैं, तो संगीतकार का उपयोग करके ऑटोलडिंग के बारे में पढ़ें।

क्या वास्तव में ऑटोलोदिंग है?

नाम मूल रूप से यह सब कहता है। आपको वह फ़ाइल प्राप्त करने की आवश्यकता नहीं है जहां अनुरोधित वर्ग को संग्रहीत किया गया है, लेकिन PHP ऑटो इसे लोड करता है।

तीसरे पक्ष के कोड के बिना मैं मूल PHP में यह कैसे कर सकता हूं?

फ़ंक्शन __autoload , लेकिन इसे spl_autoload_register का उपयोग करने के लिए बेहतर अभ्यास माना जाता है। हर बार PHP द्वारा इन कार्यों पर विचार किया जाएगा क्योंकि किसी वर्ग को दिए गए स्थान के भीतर परिभाषित नहीं किया गया है। इसलिए मौजूदा परियोजना में ऑटोलॉड को जोड़ना कोई समस्या नहीं है, क्योंकि परिभाषित कक्षाएं ( require माध्यम से) पहले की तरह काम करेंगी। पूर्वनिर्धारणता के लिए, निम्नलिखित उदाहरण अनाम फ़ंक्शंस का उपयोग करेंगे, यदि आप PHP <5.3 का उपयोग करते हैं, तो आप फ़ंक्शन को परिभाषित कर सकते हैं और इसका नाम spl_autoload_register तर्क के रूप में पास कर spl_autoload_register

उदाहरण

spl_autoload_register(function ($className) {
    $path = sprintf('%s.php', $className);
    if (file_exists($path)) {
        include $path;
    } else {
        // file not found
    }
});

ऊपर दिए गए कोड में sprintf का उपयोग करके क्लास नाम और एपेंडेड एक्सटेंशन ".php" के साथ एक फ़ाइल नाम शामिल करने का प्रयास किया गया है। यदि FooBar को लोड करने की आवश्यकता है, तो यह दिखता है कि FooBar.php मौजूद है और यदि ऐसा है तो इसे शामिल करें।

बेशक यह परियोजना की व्यक्तिगत आवश्यकता को पूरा करने के लिए बढ़ाया जा सकता है। अगर _ एक वर्ग के नाम का उपयोग समूह में किया जाता है, जैसे User_Post और User_Image दोनों User को संदर्भित करते हैं, तो दोनों वर्गों को "उपयोगकर्ता" नामक फ़ोल्डर में रखा जा सकता है जैसे:

spl_autoload_register(function ($className) {
    //                        replace _ by / or \ (depending on OS)
    $path = sprintf('%s.php', str_replace('_', DIRECTORY_SEPARATOR, $className) );
    if (file_exists($path)) {
        include $path;
    } else {
        // file not found
    }
});

वर्ग User_Post अब "User / Post.php", आदि से लोड किया जाएगा।

spl_autoload_register को विभिन्न आवश्यकताओं के अनुरूप बनाया जा सकता है। कक्षाओं के साथ आपकी सभी फ़ाइलों को "class.CLASSNAME.php" नाम दिया गया है? कोई दिक्कत नहीं है। विभिन्न घोंसले के शिकार ( User_Post_Content => "उपयोगकर्ता / पोस्ट / Content.php")? कोई समस्या भी नहीं।

यदि आप एक अधिक विस्तृत ऑटोलोडिंग तंत्र चाहते हैं - और फिर भी संगीतकार को शामिल नहीं करना चाहते हैं - आप तीसरे पक्ष के पुस्तकालयों को जोड़ने के बिना काम कर सकते हैं।

spl_autoload_register(function ($className) {
    $path = sprintf('%1$s%2$s%3$s.php',
        // %1$s: get absolute path
        realpath(dirname(__FILE__)),
        // %2$s: / or \ (depending on OS)
        DIRECTORY_SEPARATOR,
        // %3$s: don't wory about caps or not when creating the files
        strtolower(
            // replace _ by / or \ (depending on OS)
            str_replace('_', DIRECTORY_SEPARATOR, $className)
        )
    );

    if (file_exists($path)) {
        include $path;
    } else {
        throw new Exception(
            sprintf('Class with name %1$s not found. Looked in %2$s.',
                $className,
                $path
            )
        );
    }
});

इस तरह से ऑटोोलॉजिस्ट का उपयोग करके, आप खुशी से इस तरह कोड लिख सकते हैं:

require_once './autoload.php'; // where spl_autoload_register is defined

$foo = new Foo_Bar(new Hello_World());

कक्षाओं का उपयोग करना:

class Foo_Bar extends Foo {}
class Hello_World implements Demo_Classes {}

इन उदाहरणों में foo/bar.php , foo.php , hello/world.php और demo/classes.php से कक्षाएं शामिल foo.php

अनाम कक्षाएं

बेनामी कक्षाओं को आसानी से बनाए जाने वाले त्वरित एक-बंद वस्तुओं को सक्षम करने के लिए PHP 7 में पेश किया गया था। वे विधायक तर्क ले सकते हैं, अन्य वर्गों का विस्तार कर सकते हैं, इंटरफेस लागू कर सकते हैं, और सामान्य वर्ग की तरह लक्षण का उपयोग कर सकते हैं।

अपने सबसे बुनियादी रूप में, एक अनाम वर्ग निम्नलिखित की तरह दिखता है:

new class("constructor argument") {
    public function __construct($param) {
        var_dump($param);
    }
}; // string(20) "constructor argument"

एक अन्य वर्ग के अंदर एक अनाम वर्ग को घोंसले में डालना उस बाहरी वर्ग के निजी या संरक्षित तरीकों या गुणों तक पहुंच नहीं देता है। बाहरी वर्ग को अनाम वर्ग से निकालकर बाहरी वर्ग की संरक्षित विधियों और गुणों तक पहुँच प्राप्त की जा सकती है। बाहरी वर्ग के निजी गुणों तक पहुंच उन्हें अनाम वर्ग के निर्माता के माध्यम से पारित करके प्राप्त की जा सकती है।

उदाहरण के लिए:

class Outer {
    private $prop = 1;
    protected $prop2 = 2;

    protected function func1() {
        return 3;
    }

    public function func2() {
        // passing through the private $this->prop property
        return new class($this->prop) extends Outer {
            private $prop3;

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

            public function func3() {
                // accessing the protected property Outer::$prop2
                // accessing the protected method Outer::func1()
                // accessing the local property self::$prop3 that was private from Outer::$prop
                return $this->prop2 + $this->func1() + $this->prop3;
            }
        };
    }
}

echo (new Outer)->func2()->func3(); // 6

एक बुनियादी वर्ग को परिभाषित करना

PHP में एक ऑब्जेक्ट में चर और फ़ंक्शन होते हैं। वस्तुएँ आम तौर पर एक वर्ग से संबंधित होती हैं, जो उन चर और कार्यों को परिभाषित करती है, जिनमें इस वर्ग की सभी वस्तुएँ शामिल होती हैं।

एक वर्ग को परिभाषित करने के लिए वाक्यविन्यास है:

class Shape {
    public $sides = 0;
    
    public function description() {
        return "A shape with $this->sides sides.";
    }
}

एक वर्ग के परिभाषित होने के बाद, आप एक उदाहरण बना सकते हैं:

$myShape = new Shape();

ऑब्जेक्ट पर चर और फ़ंक्शन इस तरह से एक्सेस किए जाते हैं:

$myShape = new Shape();
$myShape->sides = 6;

print $myShape->description(); // "A shape with 6 sides"

निर्माता

कक्षाएं एक विशेष __construct() विधि को परिभाषित कर सकती हैं, जिसे ऑब्जेक्ट निर्माण के भाग के रूप में निष्पादित किया जाता है। इसका उपयोग अक्सर किसी वस्तु के प्रारंभिक मूल्यों को निर्दिष्ट करने के लिए किया जाता है:

class Shape {
    public $sides = 0;
    
    public function __construct($sides) {
        $this->sides = $sides;
    }
    
    public function description() {
        return "A shape with $this->sides sides.";
    }
}

$myShape = new Shape(6);

print $myShape->description(); // A shape with 6 sides

दूसरे वर्ग का विस्तार

कक्षा परिभाषाएँ मौजूदा वर्ग परिभाषाओं का विस्तार कर सकती हैं, नए चर और कार्यों को जोड़ने के साथ-साथ मूल वर्ग में परिभाषित लोगों को संशोधित कर सकती हैं।

यहाँ एक वर्ग है जो पिछले उदाहरण का विस्तार करता है:

class Square extends Shape {
    public $sideLength = 0;
    
    public function __construct($sideLength) {
       parent::__construct(4);
       
       $this->sideLength = $sideLength;
    }
    
    public function perimeter() {
        return $this->sides * $this->sideLength;
    }

    public function area() {
        return $this->sideLength * $this->sideLength;
    }
}

Square वर्ग दोनों के लिए चर और व्यवहार में शामिल Shape वर्ग और Square वर्ग:

$mySquare = new Square(10);

print $mySquare->description()/ // A shape with 4 sides

print $mySquare->perimeter() // 40

print $mySquare->area() // 100


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow