PHP Object Oriented Programming পর্ব-১৪: PHP OOP Traits

PHP OOP তে trait কি?

PHP OOP Trait

সাধারণত PHP কে বলা হয় Single Inheritance Language অর্থাৎ, PHP Language টি Multiple Inheritance সাপোর্ট করেনা। আর Trait হচ্ছে PHP OOP তে Single Inheritance এর সীমাবদ্ধতা দূর করার এবং Multiple Inheritance ব্যবহার করার একটি নতুন concept . যা PHP 5.4 এ প্রথম ব্যবহার করা হয়। Traits অনেকটা class এর মতোই, Trait কে Define করা হয় ক্লাসের মত করেই trait কিওয়ার্ডটি ব্যবহার করে। তবে এর থেকে class এর মত object তৈরী করা যায়না। কিন্তু একাধিক trait এর property এবং Method গুলোকে একটি single class এর মধ্যে ব্যবহার করা যায়। এবার চলুন একটা উদাহরণের মাধ্যমে আরো ভালো ভাবে বুঝা যাক :

File Name: foo.php

<?php
trait Foo
 {
    public function sayHello(){
         return "Hello";
    }
    public function sayWorld(){
     return "World";
    }
 }
?>

use কীওয়ার্ড ব্যবহার করে Trait কে ক্লাসে ব্যবহার করা হয়। চলুন trait ব্যবহার করে একটা উদাহরণ দেখা যাক :

File Name: bar.php

<?php
include("foo.php");
class Bar{
    // Using the Trait Here
     use Foo;
}

 $obj = new Bar;

 // Executing the method from trait
 $obj->sayHello(); //Hello
 $obj->sayWorld(); // World
?>

ব্যাখ্যা: লক্ষ্য করুন foo নামক trait কে use keyword দিয়ে bar class এর মধ্যে ব্যবহার করি, আর এতে আমরা bar এর object দিয়ে খুব সহজে foo trait এর method এবং property গুলো ব্যবহারের সুযোগ পাই।

Zend Certified PHP Engineering (ZCPE) Course

traits এবং class এর মধ্যে কার Precedence বা অগ্রাধিকার আগে?

কাজ করার ক্ষেত্রে অনেক সময় দেখা যায়, একই নামের function একই সাথে trait, parent class এবং child class এ পাওয়া যায়, তখন প্রথমে child class এর Method পাবে, তারপর trait এর মধ্যে method টি পাবে, তারপর parent class এর method টি পাবে।
চলুন একটা উদাহরণের মাধ্যমে দেখা যাক :

 <?php
 class Base{
     public function sayHello(){
         echo "say hello from base";
    }
}

trait trt{
    public function sayHello(){
        echo "say hellow from trait";
    }
}

class Child extends Base{

    use trt;
    public function sayHello(){
        echo "hello from child class";
    }
}

$objCls = new Child;

$objCls->sayHello();

?>
 

Result

 hello from child class 

এখন যদি আপনি child class এর sayHello() Method টি off অর্থাৎ comment দিয়ে hide করে রাখেন, তাহলে trt trait এর sayHello() Method execute হবে। চলুন একটা উদাহরণের মাধ্যমে দেখা যাক :

 <?php
 class Base{
     public function sayHello(){
         echo "say hello from base";
    }
}

trait trt{
    public function sayHello(){
        echo "say hellow from trait";
    }
}

class Child extends Base{

    use trt;
   /* public function sayHello(){
        echo "hello from child class";
    }*/
}

$objCls = new Child;

$objCls->sayHello();

?>
 

Result:

say hellow from trait

কিভাবে একটা class এ একাধিক trait ব্যবহার করা যায়?

Zend Certified PHP Engineering (ZCPE) Course

একটা class এ একাধিক trait ব্যবহার করতে হলে class এর মধ্যে use keyword এর পর প্রতিটি trait কে একটির পর আরেকটি comma দিয়ে দিয়ে লিখতে হয়। চলুন একটা উদাহরণের মাধ্যমে দেখা যাক :

<?php
trait Subscriber{
    public function subscriberLogin() {
        echo "You\'re Logged in as Subscriber". '<br/>';
    }
}

trait Contributor{
    public function contributorLogin() {
        echo "You're Logged in as Contributor". '<br/>';
    }

}

trait Author{
    public function AuthorLogin() {
        echo "You're Logged in as Author." . '<br/>';
    }
}

trait Administrator{
    public function AdministratorLogin(){
        echo "You're Logged in as Administrator" . '<br/>';
    }
}

class Member{
    use Subscriber, Contributor, Author, Administrator;
    public function run() {
        $this->subscriberLogin();
        $this->contributorLogin();
        $this->AuthorLogin();
        $this->AdministratorLogin();
        echo 'Members Login...done' . '<br/>';
    }
}

$authentication = new Member();

$authentication->run();

?>

Result:

You’re Logged in as Subscriber

You’re Logged in as Contributor

You’re Logged in as Author.

You’re Logged in as Administrator

Members Login…done

PHP OOP তে trait এর Conflict Resolution কি?

Zend Certified PHP Engineering (ZCPE) Course

অনেক সময়, যদি একটি class এ একাধিক trait ব্যবহার করে এবং এবং একাধিক class এ trait এ যদি একই নামে Method থাকে, আপনি যদি একাধিক trait ই একটি class এ ব্যবহার করেন তবে এটি আপনাকে fatal error দেখাবে। আর এই ব্যাপারটিকে বলা হয় Conflict Resolution. আর আমরা যদি insteadof operator দিয়ে compiler কে বলে দেন, যে একই নামের একাধিক Method এর মধ্যে কোন Method টি ব্যবহার হবে,অথবা method গুলোকে alias করে নেই , তাহলে আর কোনো error দেখাবেনা। চলুন একটা উদাহরণের মাধ্যমে দেখা যাক :

 <?php

trait Foo{
    public function first_function(){
        echo "From Foo Trait";
    }
}

trait Bar{
    public function first_function(){
        echo "From Bar Trait";
    }
}

class FooBar{
    use Foo, Bar{
        // This class will now call the method
        // first function from Foo only
        Foo::first_function insteadof Bar;
    }
}

$obj = new FooBar;

$obj->first_function();

?>

Result

 From Foo Trait 

ব্যাখ্যা: মূলতঃ আমরা ১৯ নম্বর লাইনে বলে দিয়াছি , এখানে Foo trait এর first_function টি ব্যবহৃত হোক, trait Bar এর টা নয়।

এবার চলুন aliasing ব্যবহার করে একটা উদাহরণ দেখা যাক :

<?php
trait Foo{
    public function first_function(){
        echo "From Foo Trait";
    }
}

trait Bar{
    public function first_function(){
        echo "From Bar Trait";
    }

}

class FooBar{
    use Foo, Bar{
        // This class will now call the method
        // first function from Foo Trait only\
        Foo::first_function insteadof Bar;
        // first_function of Bar can be
        // accessed with second_function
        Bar::first_function as second_function;
    }
}

$obj = new FooBar;

// Output: From Foo Trait

$obj->first_function();

// Output: From Bar Trait

$obj->second_function();

?>

ব্যাখ্যা: মূলতঃ আমরা ১৯ নম্বর লাইনে বলে দিয়াছি , এখানে Foo trait এর first_function টি ব্যবহৃত হোক, trait Bar এর টা নয়। আবার ২২ নম্বর লাইনে আমরা Bar trait এর first_function টিকে aliasing করে second_function নাম দিয়েছি।

Class এর মধ্যে ব্যবহৃত Traits এর method গুলোর default visibility পরিবর্তনের উপায় কি?

Zend Certified PHP Engineering (ZCPE) Course

সাধারণত class এর মতো trait এর method গুলোর visibility public,private এবং protected ঘোষণা করা যায়, তখন আপনি চাইল trait এর মধ্যের Method গুলোকে class এর মধ্যে as কীওয়ার্ড দিয়ে পরিবর্তন করতে পারবেন। নিচের উদাহরণটি দেখুন :

<?php
trait visible{
    public function pub(){
        echo "this is public method";
    }
    private function priv(){
        echo "this is private";
    }
    protected function proc(){
        echo "echo this is protected function";
    }
}

class cls{
    use visible{
        priv as public;
    }
    function callPriv(){
        $this->priv();
    }
}

$objCls = new cls();

$objCls->pub();//echo this is public method

//$objCls->priv();//This is private

$objCls->callPriv(); //this is private

?>

traits এর মধ্যে একাধিক trait এর ব্যবহার

use কীওয়ার্ড ব্যবহার করে আমরা একটি trait এর মধ্যে একাধিক trait এর ব্যবহার করতে পারি। নিচের উদাহরণটি দেখুন :

<?php
trait Hello{
    function sayHello() {
        echo "Hello";
    }
}

trait World{
    function sayWorld(){
        echo "World";
    }
}

trait HelloWorld{
    use Hello, World;
}

class MyWorld{
    use HelloWorld;
}

$world = new MyWorld();

echo $world->sayHello() . " " . $world->sayWorld(); //Hello World

?>

ব্যাখ্যা: লাইন নম্বর ১৫ তে লক্ষ করুন , ট্রেইট HelloWorld এ আমরা Hello এবং World নামে দুটি trait ব্যবহার করেছি।

traits এর মধ্যের properties গুলোকে class এ ব্যবহার :

কোনো trait কে class এর মধ্যে ব্যবহার করার পর , trait এ অবস্থিত একই নামের property কে class এ define করা যায়না, তারপর ও যদি কেও trait এ অবস্থিত একই নামের property কে class এ define করে , সেক্ষেত্রে যদি property value যদি same হয় তাহলে PHP কোনো error বা warning দেখাবেনা , আর যদি value ও same না হয় , তাহলে PHP Fatal Error দেখাবে। নিচের উদাহরণটি দেখুন :

<?php
trait Calories {
    public $banana = 105;
    public $cake = 300;
    public $donation = 205;
}

class Cookbook {
    use Calories;
}

$c = new Cookbook;
echo $c->banana;
?>

Result

105

এবার আমরা ভিন্ন value দিয়ে check করব।

<?php
trait Calories {
    public $banana = 105;
    public $cake = 300;
    public $donation = 205;
}

class Cookbook {
    use Calories;
    public $cake=400;
}

$c = new Cookbook;
echo $c->banana;
?>

Output

Fatal error:  Cookbook and Calories define the same property ($cake) in the composition of Cookbook. However, the definition differs and is considered incompatible. Class was composed in [...][...] on line 8

ব্যাখ্যা: লক্ষ্য করুন , লাইন নম্বর ১০ এ আমরা $cake এর 300 এর পরিবর্তে 400 দিয়েছি, যার দরুন PHP আমাদের কে fatal error দেখাচ্ছে।

Zend Certified PHP Engineering (ZCPE) Course

Trait এর মধ্যে static Property এবং Method এর ব্যবহার :

PHP তে Traits এর মধ্যে static Property এবং Method দুটিই support করে। নিচের উদাহরণটি দেখুন :

<?php
trait Calories {
    public $banana = 105;
    public $cake = 300;
    static public $donation = 205;
    
    public static function test(){
        return self::$donation;
    }
}

class Cookbook {
    use Calories;
    
}

$c = new Cookbook;
echo Cookbook::$donation;
echo "\n";
echo Cookbook::test();
?>

Trait এর মধ্যে abstract Method এর ব্যবহার :

আপনি চাইলে Traits এ abstract Method ঘোষণা করতে পারেন। আর যদি কোনো trait এ abstract Method থাকে, তখন abstract Method যুক্ত trait টি যেই class এ ব্যবহৃত হবে, সেই ক্লাস এ অবশ্যই abstract Method টি body সহ পুনরায় ঘোষণা করতে হবে। নিচের উদাহরণটি দেখুন :

<?php

trait Helper {
    abstract public function greet();
}

class Foo {
    use Helper;
    public function greet($name){
        printf('Hi there %s !', $name);
    }
}

$foo = new Foo;

$foo->greet('Awesome Man');
?>

Result

Hi there Awesome Man !

Trait ব্যবহার করে একটা sorting উদাহরণ :

<?php
trait SortStrategy {
    private $sort_field = null;
    private function string_asc($item1, $item2) {
        return strnatcmp($item1[$this->sort_field], $item2[$this->sort_field]);
    }
    private function string_desc($item1, $item2) {
        return strnatcmp($item2[$this->sort_field], $item1[$this->sort_field]);
    }
    private function num_asc($item1, $item2) {
        if ($item1[$this->sort_field] == $item2[$this->sort_field]){
            return 0;
        }
            return ($item1[$this->sort_field] < $item2[$this->sort_field] ? -1 : 1 );
    }
    private function num_desc($item1, $item2) {
        if ($item1[$this->sort_field] == $item2[$this->sort_field]){
            return 0;
        }
            return ($item1[$this->sort_field] > $item2[$this->sort_field] ? -1 : 1 );
    }
    private function date_asc($item1, $item2) {
        $date1 = intval(str_replace('-', '', $item1[$this->sort_field]));
        $date2 = intval(str_replace('-', '', $item2[$this->sort_field]));
        if ($date1 == $date2){
            return 0;
        }
        return ($date1 < $date2 ? -1 : 1 );
    }
    private function date_desc($item1, $item2) {
        $date1 = intval(str_replace('-', '', $item1[$this->sort_field]));
        $date2 = intval(str_replace('-', '', $item2[$this->sort_field]));
        if ($date1 == $date2){
            return 0;
        }
        return ($date1 > $date2 ? -1 : 1 );
    }
}

class Product {
    public $data = array();
    use SortStrategy;
    public function get() {
        // do something to get the data, for this ex. I just included an array
        $this->data = array(
            101222 => array('label' => 'Awesome product', 'price' => 10.50, 'date_added' => '2012-02-01'),
            101232 => array('label' => 'Not so awesome product', 'price' => 5.20, 'date_added' => '2012-03-20'),
            101241 => array('label' => 'Pretty neat product', 'price' => 9.65, 'date_added' => '2012-04-15'),
            101256 => array('label' => 'Freakishly cool product', 'price' => 12.55, 'date_added' => '2012-01-11'),
            101219 => array('label' => 'Meh product', 'price' => 3.69, 'date_added' => '2012-06-11'),
        );
    }
    public function sort_by($by = 'price', $type = 'asc') {
        if (!preg_match('/^(asc|desc)$/', $type)) $type = 'asc';
        switch ($by) {
            case 'name':
                $this->sort_field = 'label';
                uasort($this->data, array('Product', 'string_'.$type));
                break;
            case 'date':
                $this->sort_field = 'date_added';
                uasort($this->data, array('Product', 'date_'.$type));
                break;
            default:
                $this->sort_field = 'price';
                uasort($this->data, array('Product', 'num_'.$type));
            }
        }
    }

$product = new Product();
$product->get();
$product->sort_by('date');
?>
<table border="1" width="100%">
    <tr>
        <th>SL</th>
        <th>Label</th>
        <th>Price</th>
        <th>Date Added</th>
    </tr>
    <?php
        $i=1;
        foreach($product->data as $value){
            extract($value);
    ?>
    <tr>
        <td><?php echo $i++; ?></td>
        <td><?php echo $label; ?></td>
        <td><?php echo $price; ?></td>
        <td><?php echo $date_added; ?></td>
    </tr>
    <?php
    }
    ?>
</table>

Output

PHP Sorting with Traits

আমি মাসুদ আলম, বাংলাদেশের ৩৬ তম Zend Certified Engineer । ২০০৯ সালে কম্পিউটার সাইন্স থেকে বেচেলর ডিগ্রী অর্জন করি। দীর্ঘ ১৫ বছর আমি Winux Soft, SSL Wireless, IBCS-PRIMAX, Max Group, Canadian International Development Agency (CIDA), Care Bangladesh, World Vision, Hellen Keller, Amarbebsha Ltd সহ বিভিন্ন দেশি বিদেশী কোম্পানিতে ডেটা সাইন্স, মেশিন লার্নিং, বিগ ডেটা, ওয়েব ডেভেলপমেন্ট এবং সফটওয়্যার ডেভেলপমেন্ট এর উপর বিভিন্ন লিডিং পজিশন এ চাকরি এবং প্রজেক্ট লিড করি। এছাড়াও বাংলাদেশের ১৮৫ জন জেন্ড সার্টিফাইড ইঞ্জিনিয়ার এর মধ্যে ১২০ এরও অধিক ছাত্র আমার হাতে জেন্ড সার্টিফাইড ইঞ্জিনিয়ার হয়েছেন। বর্তমানে w3programmers ট্রেনিং ইনস্টিটিউট এ PHP এর উপর Professional এবং Advance Zend Certified PHP -8.2 Engineering, Laravel Mastering Course with ReactJS, Python Beginning To Advance with Blockchain, Machine Learning and Data Science, Professional WordPress Plugin Development Beginning to Advance কোর্স করাই। আর অবসর সময়ে w3programmers.com এ ওয়েব টেকনোলজি নিয়ে লেখালেখি করি।

3 thoughts on “PHP Object Oriented Programming পর্ব-১৪: PHP OOP Traits

Leave a Reply