PHP Object Oriented Programming
PHP Object Oriented Programming পর্ব-১৪: PHP OOP Traits
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 গুলো ব্যবহারের সুযোগ পাই।
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 ব্যবহার করা যায়?
একটা 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 কি?
অনেক সময়, যদি একটি 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 পরিবর্তনের উপায় কি?
সাধারণত 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 দেখাচ্ছে।
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
3 thoughts on “PHP Object Oriented Programming পর্ব-১৪: PHP OOP Traits”
Leave a Reply
You must be logged in to post a comment.
very good
Bangla best resource in oop php
Sir really nice tutorial