• 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
multiple inheritance یا وراثت چندگانه
#1
خیلی وقته که خیلی زبانها وراثت چندگانه رو به دلیل تار عنکبوتی شدن رابطه ها و خروج از استانداره ای رنامه نویسی پشتیبانی نمیکنن.
PHP هم وقتی شی گرا شد همین روند رو پیش گرفت ولی وراثت چند گانه رو تو برنامه ش نذاشت.
اما بعضی از مواقع هست که واقعا لازمه از وراثت چند گانه استفاده بشه. راه حل؟
در مقاله ای که در زیر آدرسش رو میدم توضیحات خوب و بامثالهای متعددی داده:
http://www.adaniels.nl/articles/how-i-ph...heritance/

نگارنده ابتدا روش های عادی رو بررسی کرده:

کد پی‌اچ‌پی:
<?php
 
abstract class FsNode
{
  public 
$path;
 
  public function 
__construct($path) {
    
$this->path $path;
  }
 
  public function 
rename($newname) {
    
rename($this->path$newname);
    
$this->path $newname;
  }
}
 
class 
File extends FsNode
{
  public function 
getContents() {
    return 
file_get_contents($this->path);
  }
}
 
class 
Dir extends FsNode
{
  public function 
scandir() {
    return 
scandir($this->path);
  }
}
 
class 
Symlink
{
  protected 
$node;
 
  public function 
__construct($node) {
    
$this->node  $node;
  }
 
  public function 
target($resolve=false) {
    return 
$resolve realpath($this->node->path) : readlink($this->node->path);
  }
 
  public function 
__call($method$args) {
    return 
call_user_func_array(array($this->node$method), $args);
  }
}
 
$dir = new Dir("/proc");
$linktodir = new Symlink(new Dir("/proc/self"));
 
var_dump($linktodir->scandir()); // Will be called through __call()
echo $linktodir->target(true), "\n"

نگارنده در ادامه این روش را غیر قابل توسعه و در صورت توسعه منجر به کاهش کارایی توصیف کرده. البته راست هم میگه چون در جاهایی که به اینصورت قرار باشه چندتا موجودیت در کنارهم استفاده بشه مشکل وجود داره. این یک مثال و نمی شه به همه ی موارد تعمیم ش داد.
نکته جالب استفاده از delegation تو مثال اولی هست. ببینید چقدر جالب متد موردنظرش رو از کلاس دیگه ای فراخونی کرده.

به کد دوم دقت کنید :

کد پی‌اچ‌پی:
abstract class FsNode
{
  public 
$mixin;
  public 
$path;
 
  public function 
__construct($path$mixin=null) {
    
$this->path $path;
    
$this->mixin $mixin;
  }
 
  function 
rename($newname) {
    
rename($this->path$newname);
    
$this->path $newname;
  }
 
  public  function 
__call($method$args) {
    if (isset(
$this->mixin) && ctype_alnum($method) && is_callable(array($this->mixin$method))) {
      return eval(
"return {$this->mixin}::$method(" . (!empty($args) ? '$args[' join('], $args['array_keys($args)) . ']' '') . ");");
    }
    
trigger_error("Call to undefined method " get_class($this) . "::$method()"E_USER_ERROR);
  }
}
 
class 
File extends FsNode
{
  public function 
getContents() {
    return 
file_get_contents($this->path);
  }
}
 
class 
Dir extends FsNode
{
  public function 
scandir() {
    return 
scandir($this->path);
  }
}
 
class 
Symlink extends FsNode
{
  public function 
target($resolve=false) {
    return 
$resolve realpath($this->path) : readlink($this->path);
  }
}
 
$dir = new Dir("/proc");
$linktodir = new Dir("/proc/self"'Symlink');
 
var_dump($linktodir->scandir());
echo 
$linktodir->target(true), "\n"// Will be called through __call() 

تو کد اول همه ی فراخوانی ها و نگاه ها به Symlink معطوف بود.
تو کد دوم برنامه نویس با استفاده از فرخوانی ها استاتیک متد از داخل کلاس تونسته از یک کلاس ارث ببره و از کلاس دیگه به همین روش استفاده کنه. به خاطر همین اومده __call رو تو کلاس پایه که اتفاقا انتزاعی هم هست به روش خودش تغییر داده. نکته ی مهم نداشتن اینستنس از کلاسی هست که به ارث نرفته . یعنی همون استفاده از "::" دونقطه است.

تو کد آخر برنامه نویس اومده Mixin رو که در واقع همو نام کلاس موردنظرش هست رو خودش تولید کرده. ضمنا Symlink تبدیل به Interface شده. این برای این منظوره که زمانی Miuxin تولید میشه و کلاس های مورد نظرذ برای استفاده فراخوانی میشن به نوعی از جنس Symlink باشن Smile

کد پی‌اچ‌پی:
abstract class FsNode
{
  protected 
$mixin;
  
// Same as above
}
 
class 
File extends FsNode
{
  
// Same as above
}
 
class 
Dir extends FsNode
{
  
// Same as above
}
 
interface 
Symlink
{}
 
abstract class 
Symlink_Methods extends FsNode
{
  public function 
target($resolve=false) {
    return 
$resolve realpath($this->path) : readlink($this->path);
  }
}
 
class 
SymlinkFile extends File implements Symlink
{
  protected 
$mixin 'Symlink_Methods';
}
 
class 
SymlinkDir extends Dir implements Symlink
{
  protected 
$mixin 'Symlink_Methods';
}
 
$dir = new Dir("/proc");
$linktodir = new Dir("/proc/self"'Symlink');
 
var_dump($linktodir->scandir());
echo 
$linktodir->target(true), "\n"// Will be called through __call()
 
if ($dir instanceof Dir)  ; // True
if ($dir instanceof Symlink)  ; // False
if ($linktodir instanceof Dir)  ; // True
if ($linktodir instanceof Symlink)  ; // True 



امید وارم مفید واقع شده باشه
علم تاج افتخار دنیا و یادگار پس از مرگ است
  پاسخ
تشکر شده توسط : admin Y.P.Y zoghal Na3r HiddeN


پرش به انجمن:


کاربران در حال بازدید این موضوع: 1 مهمان