পিএইচপিতে নেস্টেড বা ইনার ক্লাস


111

আমি আমার নতুন ওয়েবসাইটের জন্য একটি ইউজার ক্লাস তৈরি করছি, তবে এবার আমি এটিকে কিছুটা আলাদাভাবে তৈরি করার কথা ভাবছিলাম ...

সি ++ , জাভা এবং এমনকি রুবি (এবং সম্ভবত অন্যান্য প্রোগ্রামিং ভাষাগুলি) প্রধান শ্রেণীর ভিতরে নেস্টেড / অভ্যন্তরীণ শ্রেণীর ব্যবহারের অনুমতি দিচ্ছে, যা আমাদের কোডকে আরও অবজেক্ট-ভিত্তিক এবং সংগঠিত করার অনুমতি দেয়।

পিএইচপি-তে, আমি এরকম কিছু করতে চাই:

<?php
  public class User {
    public $userid;
    public $username;
    private $password;

    public class UserProfile {
      // some code here
    }

    private class UserHistory {
      // some code here
    }
  }
?>

এটি কি পিএইচপি সম্ভব? আমি কীভাবে এটি অর্জন করতে পারি?


হালনাগাদ

যদি এটি অসম্ভব, তবে ভবিষ্যতে পিএইচপি সংস্করণগুলি নেস্টেড ক্লাসগুলিকে সমর্থন করতে পারে?


4
পিএইচপি-তে এটি অসম্ভব
ইউজিন

আপনি এটি প্রসারিত করতে পারেন User, উদাহরণস্বরূপ: public class UserProfile extends Userএবং public class UserHestory extends User
ডেভ চেন

আপনি একটি বিমূর্ত ব্যবহারকারীর ক্লাস দিয়ে শুরু করতে পারেন, তারপরে এটি প্রসারিত করুন। php.net/manual/en/language.oop5.abstract.php
ম্যাথু ব্লাঙ্কার্টে

@ ডেভচেন আমি ক্লাস সম্প্রসারণের সাথে পরিচিত তবে আমি আরও ভাল
ওওপি

4
প্রসারিত করা নিয়ন্ত্রণের মতো নয় ... আপনি যখন প্রসারিত করবেন তখন আপনি 3 বার ব্যবহারকারীর শ্রেণির সদৃশ পাবেন (ব্যবহারকারী হিসাবে, ব্যবহারকারী হিসাবে ব্যবহারকারী, এবং ব্যবহারকারীর ইতিহাস হিসাবে)
ডব্লু

উত্তর:


136

ইন্ট্রো:

নেস্টেড ক্লাসগুলি বাইরের ক্লাসগুলির চেয়ে কিছুটা আলাদাভাবে অন্যান্য ক্লাসের সাথে সম্পর্কিত। জাভা উদাহরণ হিসাবে গ্রহণ:

স্থিতিহীন নেস্টেড ক্লাসগুলিকে বেসরকারী হিসাবে ঘোষণা করা হলেও, ঘের ক্লাসের অন্যান্য সদস্যদের অ্যাক্সেস রয়েছে। এছাড়াও, অ-স্থিত নেস্টেড ক্লাসগুলিকে তাত্ক্ষণিকভাবে অভিভাবক শ্রেণীর উদাহরণ প্রয়োজন।

OuterClass outerObj = new OuterClass(arguments);
outerObj.InnerClass innerObj = outerObj.new InnerClass(arguments);

এগুলি ব্যবহারের জন্য বেশ কয়েকটি বাধ্যতামূলক কারণ রয়েছে:

  • এটি যৌক্তিকভাবে শ্রেণিবদ্ধ করার একটি উপায় যা কেবলমাত্র এক জায়গায় ব্যবহৃত হয়।

কোনও শ্রেণি যদি কেবলমাত্র অন্য একটি শ্রেণির জন্য কার্যকর হয় তবে তা class শ্রেণিতে এটি সম্পর্কিত এবং এম্বেড করা এবং দুটিকে একসাথে রাখা যুক্তিযুক্ত।

  • এটি এনক্যাপসুলেশন বৃদ্ধি করে।

দুটি শীর্ষ-স্তরের শ্রেণি, এ এবং বি বিবেচনা করুন, যেখানে বি এর এ সদস্যদের অ্যাক্সেস প্রয়োজন যা অন্যথায় ব্যক্তিগত হিসাবে ঘোষণা করা হবে। এ ক্লাস এ এর ​​মধ্যে ক্লাস বি লুকিয়ে রাখলে এ এর ​​সদস্যদের ব্যক্তিগত ঘোষণা করা যেতে পারে এবং বি সেগুলি অ্যাক্সেস করতে পারে। এছাড়াও, খ নিজেই বাইরের বিশ্ব থেকে আড়াল হতে পারে।

  • নেস্টেড ক্লাসগুলি আরও পঠনযোগ্য এবং রক্ষণাবেক্ষণযোগ্য কোডের দিকে নিয়ে যেতে পারে।

একটি নেস্টেড ক্লাস সাধারণত এটির প্যারেন্ট ক্লাসের সাথে সম্পর্কিত হয় এবং একসাথে একটি "প্যাকেজ" গঠন করে

পিএইচপি-তে

নেস্টেড ক্লাস ছাড়া আপনার পিএইচপি তে অনুরূপ আচরণ থাকতে পারে ।

আপনি যা অর্জন করতে চান তা হ'ল কাঠামো / সংগঠন, প্যাকেজ.অউটারক্লাস.ইনারক্লাস হিসাবে, পিএইচপি নামের স্থানগুলি যথেষ্ট হতে পারে। এমনকি আপনি একই ফাইলটিতে একাধিক নেমস্পেসও ঘোষণা করতে পারেন (যদিও মানসম্পন্ন অটোলোয়েডিং বৈশিষ্ট্যের কারণে এটি উপযুক্ত নয়)।

namespace;
class OuterClass {}

namespace OuterClass;
class InnerClass {}

আপনি যদি সদস্যের দৃশ্যমানতার মতো অন্যান্য বৈশিষ্ট্যগুলি অনুকরণ করতে ইচ্ছুক হন তবে এটি আরও একটু বেশি প্রচেষ্টা দরকার।

"প্যাকেজ" শ্রেণি সংজ্ঞায়িত করা হচ্ছে

namespace {

    class Package {

        /* protect constructor so that objects can't be instantiated from outside
         * Since all classes inherit from Package class, they can instantiate eachother
         * simulating protected InnerClasses
         */
        protected function __construct() {}

        /* This magic method is called everytime an inaccessible method is called 
         * (either by visibility contrains or it doesn't exist)
         * Here we are simulating shared protected methods across "package" classes
         * This method is inherited by all child classes of Package 
         */
        public function __call($method, $args) {

            //class name
            $class = get_class($this);

            /* we check if a method exists, if not we throw an exception 
             * similar to the default error
             */
            if (method_exists($this, $method)) {

                /* The method exists so now we want to know if the 
                 * caller is a child of our Package class. If not we throw an exception
                 * Note: This is a kind of a dirty way of finding out who's
                 * calling the method by using debug_backtrace and reflection 
                 */
                $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
                if (isset($trace[2])) {
                    $ref = new ReflectionClass($trace[2]['class']);
                    if ($ref->isSubclassOf(__CLASS__)) {
                        return $this->$method($args);
                    }
                }
                throw new \Exception("Call to private method $class::$method()");
            } else {
                throw new \Exception("Call to undefined method $class::$method()");
            }
        }
    }
}

ব্যবহারের ক্ষেত্রে

namespace Package {
    class MyParent extends \Package {
        public $publicChild;
        protected $protectedChild;

        public function __construct() {
            //instantiate public child inside parent
            $this->publicChild = new \Package\MyParent\PublicChild();
            //instantiate protected child inside parent
            $this->protectedChild = new \Package\MyParent\ProtectedChild();
        }

        public function test() {
            echo "Call from parent -> ";
            $this->publicChild->protectedMethod();
            $this->protectedChild->protectedMethod();

            echo "<br>Siblings<br>";
            $this->publicChild->callSibling($this->protectedChild);
        }
    }
}

namespace Package\MyParent
{
    class PublicChild extends \Package {
        //Makes the constructor public, hence callable from outside 
        public function __construct() {}
        protected function protectedMethod() {
            echo "I'm ".get_class($this)." protected method<br>";
        }

        protected function callSibling($sibling) {
            echo "Call from " . get_class($this) . " -> ";
            $sibling->protectedMethod();
        }
    }
    class ProtectedChild extends \Package { 
        protected function protectedMethod() {
            echo "I'm ".get_class($this)." protected method<br>";
        }

        protected function callSibling($sibling) {
            echo "Call from " . get_class($this) . " -> ";
            $sibling->protectedMethod();
        }
    }
}

পরীক্ষামূলক

$parent = new Package\MyParent();
$parent->test();
$pubChild = new Package\MyParent\PublicChild();//create new public child (possible)
$protChild = new Package\MyParent\ProtectedChild(); //create new protected child (ERROR)

আউটপুট:

Call from parent -> I'm Package protected method
I'm Package protected method

Siblings
Call from Package -> I'm Package protected method
Fatal error: Call to protected Package::__construct() from invalid context

বিঃদ্রঃ:

আমি সত্যই মনে করি না যে পিএইচপি-তে অন্তর্বিজ্ঞান অনুকরণ করার চেষ্টা করা খুব ভাল ধারণা। আমি মনে করি কোডটি কম পরিষ্কার এবং পাঠযোগ্য। এছাড়াও, পর্যবেক্ষক, ডেকরেটর বা সংমিশ্রণ প্যাটার্নের মতো সুপ্রতিষ্ঠিত প্যাটার্ন ব্যবহার করে অনুরূপ ফলাফল অর্জনের অন্যান্য উপায়ও রয়েছে। কখনও কখনও, এমনকি সহজ উত্তরাধিকার যথেষ্ট।


2
এটি দুর্দান্ত টিভি! আমি আমার ওওপি এক্সটেনশন কাঠামোর মধ্যে সেই সমাধানটি বাস্তবায়িত করতে চলেছি! (আমার গিথুব দেখুন: github.com/SparK- ক্রুজ)
স্পার্ক

21

public/ protected/ privateঅ্যাক্সেসযোগ্যতার সাথে রিয়েল নেস্টেড ক্লাসগুলি পিএইচপি 5.6 এর জন্য আরএফসি হিসাবে 2013 সালে প্রস্তাবিত হয়েছিল কিন্তু এটি তৈরি করেনি (এখনও ভোট দেওয়া হয়নি, ২০১৩ সালের পর থেকে কোনও আপডেট নেই - ২০১//১২/২৯ হিসাবে ):

https://wiki.php.net/rfc/nested_classes

class foo {
    public class bar {
 
    }
}

কমপক্ষে, বেনাম ক্লাসগুলি এটিকে পিএইচপি 7 তে পরিণত করেছে

https://wiki.php.net/rfc/anonymous_classes

এই আরএফসি পৃষ্ঠা থেকে:

ভবিষ্যতের সুযোগ

এই প্যাচ দ্বারা পরিবর্তিত পরিবর্তনগুলির অর্থ নামযুক্ত নেস্টেড ক্লাসগুলি বাস্তবায়িত করা সহজ (একটি সামান্য বিট দ্বারা)।

সুতরাং, আমরা ভবিষ্যতের কিছু সংস্করণে নেস্টেড ক্লাস পেতে পারি, তবে এটি এখনও সিদ্ধান্ত হয়নি।


12

আপনি পিএইচপি এ এটি করতে পারবেন না । তবে এটি সম্পাদন করার জন্য কার্যকরী উপায় রয়েছে।

আরও তথ্যের জন্য দয়া করে এই পোস্টটি দেখুন: পিএইচপি নেস্টেড ক্লাস বা নেস্টেড পদ্ধতিগুলি কীভাবে করবেন?

বাস্তবায়নের এই উপায়টিকে সাবলীল ইন্টারফেস বলা হয়: http://en.wikedia.org/wiki/Fluent_interface


হ্যাঁ, দুর্ভাগ্যক্রমে এটি প্রচলিত উপায়
লাইয়ার এলরম

5

পিএইচপি সংস্করণ 5.4 যেহেতু আপনি প্রতিফলনের মাধ্যমে ব্যক্তিগত নির্মাতার সাথে অবজেক্ট তৈরি করতে বাধ্য করতে পারেন create এটি জাভা নেস্টেড ক্লাসগুলি অনুকরণ করতে ব্যবহার করা যেতে পারে। উদাহরণ কোড:

class OuterClass {
  private $name;

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

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

  public function forkInnerObject($name) {
    $class = new ReflectionClass('InnerClass');
    $constructor = $class->getConstructor();
    $constructor->setAccessible(true);
    $innerObject = $class->newInstanceWithoutConstructor(); // This method appeared in PHP 5.4
    $constructor->invoke($innerObject, $this, $name);
    return $innerObject;
  }
}

class InnerClass {
  private $parentObject;
  private $name;

  private function __construct(OuterClass $parentObject, $name) {
    $this->parentObject = $parentObject;
    $this->name = $name;
  }

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

  public function getParent() {
    return $this->parentObject;
  }
}

$outerObject = new OuterClass('This is an outer object');
//$innerObject = new InnerClass($outerObject, 'You cannot do it');
$innerObject = $outerObject->forkInnerObject('This is an inner object');
echo $innerObject->getName() . "\n";
echo $innerObject->getParent()->getName() . "\n";

4

আনল ওজেলগিনের জবাব সম্পর্কে জেননের মন্তব্য অনুসারে, বেনাম ক্লাসগুলি পিএইচপি in.০ এ প্রয়োগ করা হয়েছে, যা আপনি এখনই পাবেন ঠিক তেমন নেস্টেড ক্লাসগুলির কাছাকাছি। এখানে সম্পর্কিত আরএফসি রয়েছে:

নেস্টেড ক্লাস (স্ট্যাটাস: প্রত্যাহার)

বেনাম শ্রেণি (স্থিতি: পিএইচপি 7.0 এ প্রয়োগ করা হয়)

মূল পোস্টের একটি উদাহরণ, আপনার কোডটি দেখতে এটির মতো:

<?php
    public class User {
        public $userid;
        public $username;
        private $password;

        public $profile;
        public $history;

        public function __construct() {
            $this->profile = new class {
                // Some code here for user profile
            }

            $this->history = new class {
                // Some code here for user history
            }
        }
    }
?>

এটি, যদিও একটি খুব বাজে কভিয়েট নিয়ে আসে। আপনি যদি পিএইচপিএসটারম বা নেটবিয়ানের মতো আইডিই ব্যবহার করেন এবং Userক্লাসে এই জাতীয় কোনও পদ্ধতি যুক্ত করুন :

public function foo() {
  $this->profile->...
}

... বাই বাই অটো-সমাপ্তি। আপনি যদি ইন্টারফেসের কোড করে (সলাইডে আমি), এই জাতীয় কোনও প্যাটার্ন ব্যবহার করেও এটি কেস হয়:

<?php
    public class User {
        public $profile;

        public function __construct() {
            $this->profile = new class implements UserProfileInterface {
                // Some code here for user profile
            }
        }
    }
?>

আপনার কেবলমাত্র কলগুলি যদি পদ্ধতি $this->profileথেকে না আসে __construct()(বা যে কোনও পদ্ধতিতে $this->profileসংজ্ঞায়িত করা হয়) তবে আপনি কোনও ধরণের হিন্টিং পাবেন না। আপনার সম্পত্তিটি আপনার আইডিইর জন্য মূলত "লুকানো", আপনি যদি স্বয়ংক্রিয়ভাবে সমাপ্তি, কোড গন্ধ শুঁকতে এবং রিফ্যাক্টরিংয়ের জন্য আপনার আইডিই'র উপর নির্ভর করেন তবে জীবনকে খুব শক্ত করে তোলে।


3

আপনি পিএইচপি তে এটি করতে পারবেন না। পিএইচপি "অন্তর্ভুক্ত" সমর্থন করে, তবে আপনি এটি কোনও শ্রেণির সংজ্ঞায়নের অভ্যন্তরেও করতে পারবেন না। এখানে দুর্দান্ত বিকল্পগুলি নয়।

এটি সরাসরি আপনার প্রশ্নের উত্তর দেয় না, তবে আপনি পিএইচপি ওওপি-র \ শীর্ষ \ উপর "ভীষণ কুৎসিত" সিনট্যাক্স "হ্যাকড" নেমস্পেসে "আগ্রহী হতে পারেন: http://www.php.net/manual/en/language .namespaces.rationale.php


নেমস্পেসগুলি অবশ্যই কোডটি আরও ভালভাবে সংগঠিত করতে পারে তবে এটি নেস্টেড ক্লাসগুলির মতো শক্তিশালী নয়। উত্তর করার জন্য ধন্যবাদ!
লিওর এলরম

কেন আপনি এটিকে "ভয়ঙ্কর" বলেছেন? আমি মনে করি এটি ঠিক আছে এবং অন্যান্য সিনট্যাক্স প্রসঙ্গ থেকে ভালভাবে পৃথক।
এমফি

2

এটি আরএফসি https://wiki.php.net/rfc/anonymous_class হিসাবে ভোটের জন্য অপেক্ষা করছে


1
আমি বিশ্বাস করি না এবং বেনাম শ্রেণি নেস্ট ক্লাসের কার্যকারিতা সরবরাহ করবে।
এরিক জি

1
আরএফসি পৃষ্ঠায় আপনি যদি "নেস্টেড" অনুসন্ধান করেন তবে দেখতে পাবেন এটির সমর্থন রয়েছে। জাভা উপায়ের সাথে বহুলভাবে একই নয় তবে এটি সমর্থন করে।
আনল selzselgin

3
পিএইচপি in. এ প্রয়োগ করা হয়েছে
এলেক্ট্রা

2

আমি মনে করি যে আমি নেমস্পেস ব্যবহার করে এই সমস্যার একটি মার্জিত সমাধান লিখেছি। আমার ক্ষেত্রে, অভ্যন্তরীণ বর্গের তার পিতামাতার শ্রেণিটি (জাভাতে স্থির অভ্যন্তর শ্রেণীর মতো) জানার দরকার নেই। উদাহরণ হিসাবে আমি 'ইউজার' নামে একটি ক্লাস তৈরি করেছি এবং 'টাইপ' নামে একটি সাবক্লাস তৈরি করেছি, আমার উদাহরণে ব্যবহারকারীর প্রকারের (ADMIN, OTHERS) রেফারেন্স হিসাবে ব্যবহৃত। শুভেচ্ছা।

User.php (ব্যবহারকারীর বর্গ ফাইল)

<?php
namespace
{   
    class User
    {
        private $type;

        public function getType(){ return $this->type;}
        public function setType($type){ $this->type = $type;}
    }
}

namespace User
{
    class Type
    {
        const ADMIN = 0;
        const OTHERS = 1;
    }
}
?>

Use.php (কীভাবে 'সাবক্লাস' কল করবেন তার একটি উদাহরণ)

<?php
    require_once("User.php");

    //calling a subclass reference:
    echo "Value of user type Admin: ".User\Type::ADMIN;
?>

2

আপনি পিএইচপি 7 এ এর ​​মতো করতে পারেন:

class User{
  public $id;
  public $name;
  public $password;
  public $Profile;
  public $History;  /*  (optional declaration, if it isn't public)  */
  public function __construct($id,$name,$password){
    $this->id=$id;
    $this->name=$name;
    $this->name=$name;
    $this->Profile=(object)[
        'get'=>function(){
          return 'Name: '.$this->name.''.(($this->History->get)());
        }
      ];
    $this->History=(object)[
        'get'=>function(){
          return ' History: '.(($this->History->track)());
        }
        ,'track'=>function(){
          return (lcg_value()>0.5?'good':'bad');
        }
      ];
  }
}
echo ((new User(0,'Lior','nyh'))->Profile->get)();

-6

প্রতিটি শ্রেণিকে পৃথক ফাইলে রাখুন এবং সেগুলি "প্রয়োজনীয়" করুন।

User.php

<?php

    class User {

        public $userid;
        public $username;
        private $password;
        public $profile;
        public $history;            

        public function __construct() {

            require_once('UserProfile.php');
            require_once('UserHistory.php');

            $this->profile = new UserProfile();
            $this->history = new UserHistory();

        }            

    }

?>

UserProfile.php

<?php

    class UserProfile 
    {
        // Some code here
    }

?>

UserHistory.php

<?php

    class UserHistory 
    {
        // Some code here
    }

?>
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.