همانطور که در جلسات گذشته گفته شد زمانی که بخواهیم به یک متدی که درون کلاس وجود ندارد و یا غیر public است (protected یا private) از بیرون کلاس و در قالب آبجکت دسترسی پیدا کنیم می بایست از متد call استفاده نمائیم.
در این مثال که یک ماشین حساب است قدم به قدم نحوه استفاده از این متد را توضیح خواهیم داد.
برای شروع کلاسی را بعنوان Calc تعریف می کنیم که این کلاس دو مقدار را برای محاسبه دریافت می کند و عملیات ریاضی (+-/*) را انجام می دهد.دو مقدار اولیه num1 و num2 از بیرون کلاس قابل دسترسی نیستند.
مثال:
1 2 3 4 5 6 |
<?php class Calc{ protected $num1 = 0; protected $num2 = 0; } ?> |
حال با استفاده از تابع سازنده امکان اینکه این دو مقدار از بیرون کلاس قابل مقدار دهی باشند را فراهم می کنیم.
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php class Calc{ protected $num1 = 0; protected $num2 = 0; public function __construct($val1,$val2){ $this->num1 = $val1; $this->num2 = $val2; } } ?> |
در این مرحله متدهای ریاضی خود را می نویسیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<?php class Calc{ protected $num1 = 0; protected $num2 = 0; public function __construct($val1,$val2){ $this->num1 = $val1; $this->num2 = $val2; } //add public function add(){ return $this->num1+$this->num2; } //substract public function substract(){ return $this->num1-$this->num2; } //multiply public function multiply(){ return $this->num1*$this->num2; } //divide public function divide(){ return $this->num1/$this->num2; } } ?> |
تست خروجی عملیات ریاضی در کلاس ماشین حساب
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<?php class Calc{ protected $num1 = 0; protected $num2 = 0; public function __construct($val1,$val2){ $this->num1 = $val1; $this->num2 = $val2; } //add public function add(){ return $this->num1+$this->num2; } //substract public function substract(){ return $this->num1-$this->num2; } //multiply public function multiply(){ return $this->num1*$this->num2; } //divide public function divide(){ return $this->num1/$this->num2; } } $obj = new Calc(50,20); echo "<h3>add method:".$obj->add()."</h3>"; echo "<h3>substract method:".$obj->substract()."</h3>"; echo "<h3>multiply method:".$obj->multiply()."</h3>"; echo "<h3>divide method:".$obj->divide()."</h3>"; ?> /* add method:70 substract method:30 multiply method:1000 divide method:2.5 */ |
ساخت کلاس پیشرفته
در مرحله بعد از روی Calc ارث بری می کنیم و کلاس جدیدی به نام CalcAdvanced ایجاد می کنیم.در این کلاس تابع سازنده را ایجاد کرده ایم اما این تابع مقادیر خود را به تابع پدر یعنی Calc ارسال می کند و مقادیر num1 و num2 مقدار دهی می شوند.
در این مثال با استفاده از دستور parent به تابع سازنده پدر اشاره کرده ایم و مقادیر دریافتی را به تابع سازنده پدر ارسال می کنیم.
1 2 3 4 5 |
class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } } |
در قسمت بعد خصوصیتی را بصورت private و از نوع آرایه تعریف می کنیم که این آرایه کلیدش نام تابع و مقدارش تعداد پارامترهای آن می باشد.این آرایه لیست توابعی است که ممکن است از بیرون کلاس درخواست شود. اعداد نیز تعداد پارامترهای پیش فرض تابع موردنظر است.
1 2 3 4 5 6 7 |
class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } private $allowFunctions = ["pow" => 2, "sqrt" => 1,"exp" => 1]; } |
استفاده از متد call
حال در این بخش متد call خود را که از نوع public است ایجاد می کنیم.این تابع دارای دو پارامتر است پارامتر اول نام متد و پارامتر دوم تعداد پارامترهای تابع مورد نظر است.
1 2 3 4 5 6 7 8 9 10 11 |
class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } private $allowFunctions = ["pow" => 2, "sqrt" => 1,"exp" => 1]; public function __call($methodName, $arguments){ } } |
حال باید درون این تابع دستور شرطی را قرار بدهیم که آیا methodName وارد شده از بیرون کلاس درون آرایه allowFunctions وجود دارد یا خیر در صورتی که وجود دارد عملیاتی را انجام دهد.
در این حالت با استفاده از تابع array_keys کلیدهای آرایه allowFunctions را دریافت کرده و درون تابع دیگری به نام in_array بررسی کرده ایم که آیا methodName مورد نظر در این آرایه وجود دارد یا خیر.
برای مثال از بیرون کلاس نام pow برای تابع صدا زده شده است.این واژه که همان methodName است در درون کلیدهای آرایه allowFunctions بررسی می شود که وجود دارد یا خیر.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } private $allowFunctions = ["pow" => 2, "sqrt" => 1,"exp" => 1]; public function __call($methodName, $arguments){ if(in_array($methodName,array_keys($this->allowFunctions))){ } } } |
در این مرحله و درون شرط باید آرگومان های خود را ایجاد کنیم. در مرحله اول متغیری را از نوع آرایه به نام arguments ایجاد می کنیم.
هر تابع حداقل یک پارامتر را دارد.بنابراین مقدار نخست ارسال شده در هنگام ساخت آبجکت یعنی num1 را بعنوان مقدار اول آرایه arguments در نظر می گیریم.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } private $allowFunctions = ["pow" => 2, "sqrt" => 1,"exp" => 1]; public function __call($methodName, $arguments){ if(in_array($methodName,array_keys($this->allowFunctions))){ $arguments = [$this->num1]; } } } |
حال باید بررسی کنیم در صورتی که تابع صدا زده شده methodName درون آرایه allowFunctions بیشتر از یک پارامتر دارد، مقدار بعدی به آرایه arguments اضافه شود.برای اینکار شرط خود را قرار می دهیم و برای اضافه کردن از متد array_push استفاده می کنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } private $allowFunctions = ["pow" => 2, "sqrt" => 1,"exp" => 1]; public function __call($methodName, $arguments){ if(in_array($methodName,array_keys($this->allowFunctions))){ $arguments = [$this->num1]; if($this->allowFunctions[$methodName] == 2){ array_push($arguments,$this->num2); } } } } |
در آخر نیز تابع call_user_func_array را وارد کرده و آن را برگشت می دهیم وظیفه این تابع فراخوانی تابع دیگری است که توسط کاربر تعریف شده است. این تابع دارای دو پارامتر است نام تابع که همان methodName و پارامترها در قالب آرایه که همان arguments است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } private $allowFunctions = ["pow" => 2, "sqrt" => 1,"exp" => 1]; public function __call($methodName, $arguments){ if(in_array($methodName,array_keys($this->allowFunctions))){ $arguments = [$this->num1]; if($this->allowFunctions[$methodName] == 2){ array_push($arguments,$this->num2); } return call_user_func_array($methodName,$arguments); } } } |
تست کلاس پیشرفته
برای تست از روی کلاس CalcAdvanced یک شی می سازیم و مقادیر خود را به درون آن ارسال می کنیم.در مثال زیر از تابع pow استفاده کرده ایم و مقدار خروجی برابر با ۳۲ است.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<?php class Calc{ protected $num1 = 0; protected $num2 = 0; public function __construct($val1,$val2){ $this->num1 = $val1; $this->num2 = $val2; } //add public function add(){ return $this->num1+$this->num2; } //substract public function substract(){ return $this->num1-$this->num2; } //multiply public function multiply(){ return $this->num1*$this->num2; } //divide public function divide(){ return $this->num1/$this->num2; } } class CalcAdvanced extends Calc{ public function __construct($val1,$val2){ parent::__construct($val1,$val2); } private $allowFunctions = ["pow" => 2, "sqrt" => 1,"exp" => 1]; public function __call($methodName, $arguments){ if(in_array($methodName,array_keys($this->allowFunctions))){ $arguments = [$this->num1]; if($this->allowFunctions[$methodName] == 2){ array_push($arguments,$this->num2); } return call_user_func_array($methodName,$arguments); }else{ die('not found'); } } } $obj = new CalcAdvanced(2,5); echo "<h3>pow method:".$obj->pow()."</h3>"; ?> /* pow method:32 */ |