۱۳۸۸ مهر ۰۵, ۰۲:۳۲ ب.ظ
خیلی وقته که خیلی زبانها وراثت چندگانه رو به دلیل تار عنکبوتی شدن رابطه ها و خروج از استانداره ای رنامه نویسی پشتیبانی نمیکنن.
PHP هم وقتی شی گرا شد همین روند رو پیش گرفت ولی وراثت چند گانه رو تو برنامه ش نذاشت.
اما بعضی از مواقع هست که واقعا لازمه از وراثت چند گانه استفاده بشه. راه حل؟
در مقاله ای که در زیر آدرسش رو میدم توضیحات خوب و بامثالهای متعددی داده:
http://www.adaniels.nl/articles/how-i-ph...heritance/
نگارنده ابتدا روش های عادی رو بررسی کرده:
نگارنده در ادامه این روش را غیر قابل توسعه و در صورت توسعه منجر به کاهش کارایی توصیف کرده. البته راست هم میگه چون در جاهایی که به اینصورت قرار باشه چندتا موجودیت در کنارهم استفاده بشه مشکل وجود داره. این یک مثال و نمی شه به همه ی موارد تعمیم ش داد.
نکته جالب استفاده از delegation تو مثال اولی هست. ببینید چقدر جالب متد موردنظرش رو از کلاس دیگه ای فراخونی کرده.
به کد دوم دقت کنید :
تو کد اول همه ی فراخوانی ها و نگاه ها به Symlink معطوف بود.
تو کد دوم برنامه نویس با استفاده از فرخوانی ها استاتیک متد از داخل کلاس تونسته از یک کلاس ارث ببره و از کلاس دیگه به همین روش استفاده کنه. به خاطر همین اومده __call رو تو کلاس پایه که اتفاقا انتزاعی هم هست به روش خودش تغییر داده. نکته ی مهم نداشتن اینستنس از کلاسی هست که به ارث نرفته . یعنی همون استفاده از "::" دونقطه است.
تو کد آخر برنامه نویس اومده Mixin رو که در واقع همو نام کلاس موردنظرش هست رو خودش تولید کرده. ضمنا Symlink تبدیل به Interface شده. این برای این منظوره که زمانی Miuxin تولید میشه و کلاس های مورد نظرذ برای استفاده فراخوانی میشن به نوعی از جنس Symlink باشن
امید وارم مفید واقع شده باشه
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 باشن

کد پیاچپی:
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
امید وارم مفید واقع شده باشه
علم تاج افتخار دنیا و یادگار پس از مرگ است