পিএইচপি-তে ক্লাস প্রয়োগের জন্য পদ্ধতি স্বাক্ষর পরিবর্তন করা


9

পিএইচপি-র জেনেরিক্সের অভাবের আশেপাশে এমন কোনও শালীন কাজ রয়েছে যা স্থির কোড পরিদর্শনকে ধরণের ধারাবাহিকতা সনাক্ত করতে দেয়?

আমার একটি বিমূর্ত শ্রেণি আছে, আমি উপ-শ্রেণি করতে চাই এবং এটি প্রয়োগ করতে চাই যে একটি পদ্ধতির এক ধরণের পরামিতি নেওয়া থেকে একটি পরামিতি নেওয়া যা সেই প্যারামিটারের একটি সাব-ক্লাস।

abstract class AbstractProcessor {
    abstract function processItem(Item $item);
}

class WoodProcessor extends AbstractProcessor {
    function processItem(WoodItem $item){}
}

পিএইচপি-তে এটি অনুমোদিত নয় কারণ এটি পদ্ধতি স্বাক্ষর পরিবর্তন করছে যা অনুমোদিত নয়। জাভা স্টাইল জেনারিকের সাহায্যে আপনি এরকম কিছু করতে পারেন:

abstract class AbstractProcessor<T> {
    abstract function processItem(T $item);
}

class WoodProcessor extends AbstractProcessor<WoodItem> {
    function processItem(WoodItem $item);
}

তবে অবশ্যই পিএইচপি তাদের সমর্থন করে না support

গুগল এই সমস্যার জন্য, লোকেরা instanceofরান-টাইমে যেমন ত্রুটিগুলি পরীক্ষা করতে ব্যবহার করার পরামর্শ দেয়

class WoodProcessor extends AbstractProcessor {
    function processItem(Item $item){
        if (!($item instanceof WoodItem)) {
            throw new \InvalidArgumentException(
                "item of class ".get_class($item)." is not a WoodItem");
        } 
    }
}

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

সমস্যার আরও সম্পূর্ণ উদাহরণ হ'ল:

class StoneItem extends Item{}
class WoodItem extends Item{}

class WoodProcessedItem extends ProcessedItem {
    function __construct(WoodItem $woodItem){}
}

class StoneProcessedItem extends ProcessedItem{
    function __construct(StoneItem $stoneItem){}
}

abstract class AbstractProcessor {
    abstract function processItem(Item $item);

    function processAndBoxItem(Box $box, Item $item) {
       $processedItem = $this->processItem($item);
       $box->insertItem($item);
    }

    //Lots of other functions that can call processItem
}

class WoodProcessor extends AbstractProcessor {
    function processItem(Item $item) {
        return new ProcessedWoodItem($item); //This has an inspection error
    }
}

class StoneProcessor extends AbstractProcessor {
    function processItem(Item $item) {
        return new ProcessedStoneItem($item);//This has an inspection error
    }
}

কারণ আমি শুধু একটি পার করছি Itemকরার new ProcessedWoodItem($item)এবং এটি প্যারামিটার হিসাবে একটি WoodItem আশা, কোড পরিদর্শন প্রস্তাব দেওয়া একটি ত্রুটি নেই।


1
আপনি ইন্টারফেস ব্যবহার করছেন না কেন? আপনি যা চান তা অর্জন করতে আপনি ইন্টারফেস উত্তরাধিকার ব্যবহার করতে পারেন, আমি বিশ্বাস করি।
রিবল্ড এডি

কারণ দুটি শ্রেণি তাদের কোডের 80% ভাগ করে, যা বিমূর্ত শ্রেণিতে রয়েছে। ইন্টারফেস ব্যবহারের অর্থ হয় কোডটি নকল করা, বা ভাগ করা কোডটিকে অন্য শ্রেণিতে স্থানান্তরিত করার জন্য একটি বৃহত চুল্লি যা দুটি শ্রেণীর সাথে সংমিশ্রিত হতে পারে।
ড্যানাক

আমি নিশ্চিত আপনি উভয় একসাথে ব্যবহার করতে পারবেন।
রিবল্ড এডি

হ্যাঁ - তবে এটি সমস্যার সমাধান করে না যে i) ভাগ করা পদ্ধতিগুলি 'আইটেম' এর বেস শ্রেণিটি ব্যবহার করা প্রয়োজন ii) নির্দিষ্ট ধরণের পদ্ধতিগুলি উপ-শ্রেণীর "উড আইটেম" ব্যবহার করতে চায় তবে এটি "ঘোষণার মতো ত্রুটি দেয়" উডপ্রসেসর এর :: বার () অবশ্যই অ্যাবস্ট্রাক্ট প্রসেসর :: বার (আইটেম $ আইটেম) এর সাথে সামঞ্জস্যপূর্ণ হতে হবে "
ড্যানাক

প্রকৃতপক্ষে আচরণটি পরীক্ষা করার জন্য আমার কাছে সময় নেই তবে আপনি যদি ইন্টারফেসটি ইঙ্গিত করলেন (একটি আইটেম এবং একটি আইওউডআইটি তৈরি করুন এবং আইওয়ুডআইটিম আইটেমের উত্তরাধিকার সূত্রে প্রাপ্ত হন)? তারপরে সন্তানের বেস ক্লাসের জন্য ফাংশন স্বাক্ষর এবং আইউউডআইটিমে ইন্টিস্ট আইটেম টাট কাজ করতে পারে। পারে না।
রিবল্ডএডি

উত্তর:


3

পরিবর্তে ডক-ব্লকগুলির সাথে পরামিতিগুলি ডকুমেন্ট করে আপনি কোনও যুক্তি ছাড়াই পদ্ধতি ব্যবহার করতে পারেন:

<?php

class Foo
{
    /**
     * @param string $world
     */
    public function hello()
    {
        list($world) = func_get_args();

        echo "Hello, {$world}\n";
    }
}

class Bar extends Foo
{
    /**
     * @param string $greeting
     * @param string $world
     */
    public function hello()
    {
        list($greeting, $world) = func_get_args();

        echo "{$greeting}, {$world}\n";
    }
}

$foo = new Foo();
$foo->hello('World');

$bar = new Bar();
$bar->hello('Bonjour', 'World');

আমি বলতে যাচ্ছি না আমি মনে করি এটি যদিও একটি ভাল ধারণা।

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

তাই ভালো:

<?php

class HelloContext
{
    /** @var string */
    public $greeting;

    /** @var string */
    public $world;

    public static function create($world)
    {
        $context = new self;

        $context->world = $world;

        return $context;
    }

    public static function createWithGreeting($greeting, $world)
    {
        $context = new self;

        $context->greeting = $greeting;
        $context->world = $world;

        return $context;
    }
}

class Foo
{
    public function hello(HelloContext $context)
    {
        echo "Hello, {$context->world}\n";
    }
}

class Bar extends Foo
{
    public function hello(HelloContext $context)
    {
        echo "{$context->greeting}, {$context->world}\n";
    }
}

$foo = new Foo();
$foo->hello(HelloContext::create('World'));

$bar = new Bar();
$bar->hello(HelloContext::createWithGreeting('Bonjour', 'World'));

স্থির কারখানার পদ্ধতি অবশ্যই ofচ্ছিক - তবে কেবল সদস্যদের নির্দিষ্ট নির্দিষ্ট সংমিশ্রণ একটি অর্থবহ প্রসঙ্গ তৈরি করলে তা কার্যকর হতে পারে। যদি তা হয় তবে আপনি __construct()সুরক্ষিত / ব্যক্তিগত হিসাবেও ঘোষণা করতে চাইতে পারেন wish


হুফসকে একটি পিএইচপি-র মধ্যে ওওপি অনুকরণ করতে লাফিয়ে যেতে হয়।
তুলিনাস কর্ডোভা

4
@ ব্যবহারকারী 6১5৫২ আমি পিএইচপি রক্ষা করতে (এটি বিশ্বাস করুন) বলছি না তবে বেশিরভাগ ভাষা আপনাকে উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতি-স্বাক্ষর পরিবর্তন করতে দেয় না - icallyতিহাসিকভাবে, পিএইচপি -তে এটি সম্ভব ছিল, তবে বিভিন্ন কারণে প্রোগ্রামারদের (কৃত্রিমভাবে) সীমাবদ্ধ করার সিদ্ধান্ত নেওয়া হয়েছিল এটি করা থেকে, কারণ এটি ভাষার সাথে মৌলিক সমস্যা সৃষ্টি করে; এই পরিবর্তনটি অন্য ভাষার সাথে আরও লাইন আনার জন্য করা হয়েছিল, সুতরাং আপনি কোন ভাষার সাথে তুলনা করছেন তা নিশ্চিত নই। আমার উত্তরের দ্বিতীয় অংশে প্রদর্শিত প্যাটার্নটি অন্যান্য # সি বা জাভাতেও কার্যকর এবং কার্যকর।
mindplay.dk
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.