Coming from C++ background ;)
How can I overload PHP functions?
One function definition if there are any arguments, and another if there are no arguments?
Is it possible in PHP? Or should I use if else to check if there are any parameters passed from $_GET and POST?? and relate them?
You cannot overload PHP functions. Function signatures are based only on their names and do not include argument lists, so you cannot have two functions with the same name. Class method overloading is different in PHP than in many other languages. PHP uses the same word but it describes a different pattern.
You can, however, declare a variadic function that takes in a variable number of arguments. You would use func_num_args()
and func_get_arg()
to get the arguments passed, and use them normally.
For example:
function myFunc() {
for ($i = 0; $i < func_num_args(); $i++) {
printf(\"Argument %d: %s\\n\", $i, func_get_arg($i));
}
}
/*
Argument 0: a
Argument 1: 2
Argument 2: 3.5
*/
myFunc(\'a\', 2, 3.5);
PHP doesn\'t support traditional method overloading, however one way you might be able to achieve what you want, would be to make use of the __call
magic method:
class MyClass {
public function __call($name, $args) {
switch ($name) {
case \'funcOne\':
switch (count($args)) {
case 1:
return call_user_func_array(array($this, \'funcOneWithOneArg\'), $args);
case 3:
return call_user_func_array(array($this, \'funcOneWithThreeArgs\'), $args);
}
case \'anotherFunc\':
switch (count($args)) {
case 0:
return $this->anotherFuncWithNoArgs();
case 5:
return call_user_func_array(array($this, \'anotherFuncWithMoreArgs\'), $args);
}
}
}
protected function funcOneWithOneArg($a) {
}
protected function funcOneWithThreeArgs($a, $b, $c) {
}
protected function anotherFuncWithNoArgs() {
}
protected function anotherFuncWithMoreArgs($a, $b, $c, $d, $e) {
}
}
To over load a function simply do pass parameter as null by default,
class ParentClass
{
function mymethod($arg1 = null, $arg2 = null, $arg3 = null)
{
if( $arg1 == null && $arg2 == null && $arg3 == null ){
return \'function has got zero parameters <br />\';
}
else
{
$str = \'\';
if( $arg1 != null )
$str .= \"arg1 = \".$arg1.\" <br />\";
if( $arg2 != null )
$str .= \"arg2 = \".$arg2.\" <br />\";
if( $arg3 != null )
$str .= \"arg3 = \".$arg3.\" <br />\";
return $str;
}
}
}
// and call it in order given below ...
$obj = new ParentClass;
echo \'<br />$obj->mymethod()<br />\';
echo $obj->mymethod();
echo \'<br />$obj->mymethod(null,\"test\") <br />\';
echo $obj->mymethod(null,\'test\');
echo \'<br /> $obj->mymethod(\"test\",\"test\",\"test\")<br />\';
echo $obj->mymethod(\'test\',\'test\',\'test\');
It may be hackish to some, but I learned this way from how Cakephp does some functions and have adapted it because I like the flexibility it creates
The idea is you have different type of arguments, arrays, objects etc, then you detect what you were passed and go from there
function($arg1, $lastname) {
if(is_array($arg1)){
$lastname = $arg1[\'lastname\'];
$firstname = $arg1[\'firstname\'];
} else {
$firstname = $arg1;
}
...
}
Real Overload (Version 3.8) \"without extending\" + \"support closures\"
/*******************************
* author : hishamdalal@gmail.com
* version : 3.8
* create on : 2017-09-17
*****************************/
class Overloadable
{
static function call($obj, $method, $params=null) {
$class = get_class($obj);
// Get real method name
$suffix_method_name = $method.self::getMethodSuffix($method, $params);
if (method_exists($obj, $suffix_method_name)) {
// Call method
return call_user_func_array(array($obj, $suffix_method_name), $params);
}else{
throw new Exception(\'Tried to call unknown method \'.$class.\'::\'.$suffix_method_name);
}
}
static function getMethodSuffix($method, $params_ary=array()) {
$c = \'__\';
if(is_array($params_ary)){
foreach($params_ary as $i=>$param){
// Adding special characters to the end of method name
switch(gettype($param)){
case \'array\': $c .= \'a\'; break;
case \'boolean\': $c .= \'b\'; break;
case \'double\': $c .= \'d\'; break;
case \'integer\': $c .= \'i\'; break;
case \'NULL\': $c .= \'n\'; break;
case \'object\':
// Support closure parameter
if($param instanceof Closure ){
$c .= \'c\';
}else{
$c .= \'o\';
}
break;
case \'resource\': $c .= \'r\'; break;
case \'string\': $c .= \'s\'; break;
case \'unknown type\':$c .= \'u\'; break;
}
}
}
return $c;
}
// Get a reference variable by name
static function &refAccess($var_name) {
$r =& $GLOBALS[\"$var_name\"];
return $r;
}
}
class test
{
private $name = \'test-1\';
// Call Overloadable class
// you must copy this method in your class to activate overloading
function __call($method, $args) {
return Overloadable::call($this, $method, $args);
}
// func(closure)
function func__c(Closure $callback) {
pre(\"func__c(\".print_r($callback, 1).\");\", \'print_r(Closure)\');
return $callback($this->name);
}
}
//----------------------------------------------------------
// Start
$t = new test;
pre($t->func(function($n){ return strtoupper($n);}), \'Closure\');
//----------------------------------------------------------
function pre($mixed, $title=null, $print=true){
$output = \"\";
if(empty($mixed)){
$output .= \"<div><h3>-->Empty $title<--</h3></div>\";
if($print) echo $output;
else return $output;
}
$output .= \"<fieldset>\";
if($title){$output .= \"<legend><h2>$title</h2></legend>\";}
$output .= \'<pre>\';
$output .= print_r($mixed, 1);
$output .= \'</pre>\';
$output .= \"</fieldset>\";
if($print) echo $output;
else return $output;
}
//----------------------------------------------------------
Output:
---- print_r(Closure) ----
func__c(Closure Object
(
[parameter] => Array
(
[$n] =>
)
)
);
---- Closure ----
TEST-1
Real Overload \"Without extending\" (Version 3.7)
<?php
/*******************************
* author : hishamdalal@gmail.com
* version : 3.7
* date : 2014-12-01
*****************************/
class Overloadable
{
static function call($obj, $method, $params=null) {
// Get real method name
$suffix_method_name = $method.self::getMethodSuffix($method, $params);
if (method_exists($obj, $suffix_method_name)) {
// Call method
return call_user_func_array(array($obj, $suffix_method_name), $params);
#return $obj->$suffix_method_name($params);
} else {
$class = get_class($obj);
throw new Exception(\'Tried to call unknown method \'.$class.\'::\'.$suffix_method_name);
}
}
static function getMethodSuffix($method, $params_ary=array()) {
$c = \'__\';
if( is_array($params_ary) ) {
foreach($params_ary as $i=>$param){
// Adding special characters to the end of method name
switch(gettype($param)){
case \'array\': $c .= \'a\'; break;
case \'boolean\': $c .= \'b\'; break;
case \'double\': $c .= \'d\'; break;
case \'integer\': $c .= \'i\'; break;
case \'NULL\': $c .= \'n\'; break;
case \'object\': $c .= \'o\'; break;
case \'resource\': $c .= \'r\'; break;
case \'string\': $c .= \'s\'; break;
}
}
}
return $c;
}
// Get a reference variable by name
static function &refAccess($var_name) {
$r =& $GLOBALS[\"$var_name\"];
return $r;
}
}
class test
{
// Call Overloadable class
// you must copy this method in your class to activate overloading
function __call($method, $args) {
return Overloadable::call($this, $method, $args);
}
// myFunction(void)
function myFunction__() {
echo \'myFunction(void)\';
}
// myFunction(integer)
function myFunction__i($int) {
echo \'myFunction(integer=\'.$int.\')\';
}
// myFunction(string)
function myFunction__s($string) {
echo \'myFunction(string=\'.$string.\')\';
}
// myFunction(string)
function myFunction__so($string, $object) {
echo \'myFunction(string=\'.$string.\', object=\'.get_class($object).\')\';
echo \'<pre>Object: \';
print_r($object);
echo \'</pre>\';
}
// anotherFunction(array)
function anotherFunction__a($array) {
echo \'anotherFunction(\'.print_r($array, 1).\')\';
$array[0]++; // change the reference value
$array[\'val\']++; // change the reference value
}
// anotherFunction(string, integer)
function anotherFunction__si($key, $value) {
echo \'anotherFunction(string=\'.$key.\', integer=\'.$value.\')\';
// Get a reference
$a2 =& Overloadable::refAccess($key); // $a2 =& $GLOBALS[\'val\'];
$a2 *= 3; // change the reference value
}
}
//----------------------------------------------------------
// Some data to work with:
$val = 10;
class obj {
private $x=10;
}
//----------------------------------------------------------
// Start
$t = new test;
// Call first method with no args:
$t->myFunction();
// Output: myFunction(void)
echo \'<hr>\';
$t->myFunction($val);
// Output: myFunction(integer=10)
echo \'<br>\';
$t->myFunction(\"hello\");
// Output: myFunction(string=hello)
echo \'<br>\';
$t->myFunction(\"str\", new obj());
/* Output:
myFunction(string=str, object=obj)
Object: obj Object
(
[x:obj:private] => 10
)
*/
## Passing by Reference:
echo \'<hr>\';
echo \'$val=\'.$val;
// Output: $val=10
echo \'<br>\';
$t->anotherFunction(array(&$val, \'val\'=>&$val));
// Output: anotherFunction(Array ( [0] => 10 [val] => 10 ) )
echo \'<br>\';
echo \'$val=\'.$val;
// Output: $val=12
echo \'<hr>\';
$t->anotherFunction(\'val\', $val);
// Output: anotherFunction(string=val, integer=12)
echo \'<br>\';
echo \'$val=\'.$val;
// Output: $val=36
Real Overload (Version 3.5):
/*******************************
* author : hishamdalal@gmail.com
* version : 3.5
* date : 2014-11-16
*****************************/
class Overloadable
{
// Magic Method
public function __call($method, $params) {
$class = get_class($this);
// Get real method name
$suffix_method_name = $method.$this->getMethodSuffix($method, $params);
if (method_exists($this, $suffix_method_name)){
// Call method
return call_user_func_array(array($this, $suffix_method_name), $params);
}else{
throw new Exception(\'Tried to call unknown method \'.$class.\'::\'.$suffix_method_name);
}
}
function getMethodSuffix($method, $params_ary=array()){
$c = \'__\';
if(is_array($params_ary)){
foreach($params_ary as $i=>$param){
// Adding special characters to the end of method name
switch(gettype($param)){
case \'integer\': $c .= \'i\'; break;
case \'double\': $c .= \'d\'; break;
case \'string\': $c .= \'s\'; break;
case \'array\': $c .= \'a\'; break;
case \'object\': $c .= \'o\'; break;
case \'resource\': $c .= \'r\'; break;
case \'NULL\': $c .= \'n\'; break;
}
}
}
return $c;
}
// Get reference variable by name
function &refAccess($var_name){
$r =& $GLOBALS[\"$var_name\"];
return $r;
}
}
//------------------------------------------------------------------------//
## Inherit \"Overloadable\" class to enable overloading
class test extends Overloadable
{
// myFunction(void)
function myFunction__() {
echo \"Hi<br>\";
}
// myFunction(integer, string)
function myFunction__is($a, $s) {
echo \"$a, $s<br>\";
}
// myFunction(array)
function myFunction__a($a) {
$a[0]++; // change the reference value
$a[1]++; // change value locally (method scope)
}
// myFunction(integer)
function myFunction__i($b) {
// $GLOBALS[\'val2\']
$b2 =& $this->refAccess(\'val2\');
$b2 *= 3; // change the reference value
}
// myFunction(string, string)
function myFunction__ss($a, $b) {
// $this->refAccess(\'obj\')->plus()
$this->refAccess($a)->plus();
#$b1 =& $GLOBALS[\"$b\"];
$b1 =& $this->refAccess($b);
$b1++;
$b1++;
}
// myFunction(object, integer, array)
function myFunction__oia($a, $b, $ary) {
// Get arguments names
$obj_name = $ary[0];
$val_name = $ary[1];
// Get argument reference
$a1 =& $this->refAccess($obj_name);
$a1->plus();
$b1 =& $this->refAccess($val_name);
$b1+= $b;
}
// Just a normal method
function welcome(){
echo \"Welcome!\";
}
}
//------------------------------------------------------------------------//
// Some data types to work with:
class obj {
private $v=0;
function plus(){
$this->v++;
}
function result(){
return $this->v;
}
}
$val = 10;
$val2 = 10;
$obj = new obj();
// Show Default values
echo \"\\$val = $val, \\$val2 = $val2, \";
echo \'obj->v =\' . $obj->result().\"<hr>\";
//------------------------------------------------------------------------//
// Start
$t = new test();
// Call first method with no args:
echo \'myFunction__():<br>\';
$t->myFunction();
echo \"<hr>\";
echo \'myFunction__is(integer, string):<br>\';
$t->myFunction($val, \'text\');
echo \"\\$val = $val, \\$val2 = $val2<hr>\";
echo \'myFunction__i(integer):<br>\';
$t->myFunction($val);
echo \"\\$val = $val, \\$val2 = $val2<hr>\";
## Passing by Reference:
// 1) The best way to pass arguments
echo \'myFunction__a(array):<br>\';
//Passing first item by reference
$t->myFunction(array(&$val, $val2));
echo \"\\$val = $val, \\$val2 = $val2<hr>\";
// 2) Passing arguments names
echo \'myFunction__ss(string, string):<br>\';
// Pass object name and variable name
$t->myFunction(\'obj\', \'val\');
echo \"\\$val = $val, \\$val2 = $val2, \";
echo \'obj->v =\' . $obj->result().\"<hr>\";
// 3) Passing arguments values and names
echo \'myFunction__oia(object, integer, array):<br>\';
// Pass object, integer values and passing there names as array
$t->myFunction($obj, $val, array(\'obj\', \'val\'));
echo \"\\$val = $val, \\$val2 = $val2, \";
echo \'obj->v =\' . $obj->result().\"<hr>\";
// Just a normal method
echo \'welcome():<br>\';
$t->welcome();
Real Overload (Version 3.1):
/*******************************
* author : hishamdalal@gmail.com
* version : 3.1
* date : 2013-04-11
*****************************/
class overloadable
{
protected $fname = null;
protected $fargs = array();
//--------------------------------------------------//
function set($obj, $fname, $args){
$n = \'\';
$type = $this->getType($args);
$n = \"\\$o = new $obj();\\n\";
$n .= \"if(method_exists(\\$o, \'$fname\".\"_$type\')){\\n\";
$n .= \"\\t\\$r = \\$o->$fname\".\"_$type(\". $this->getArgsName($args) .\");\\n\";
$n .= \"}else{\\n\\t\\$r = null;\\n\";
$n .= \"\\ttrigger_error(\'function \".$fname.\"_\".$type.\" is not exist!\');\\n}\";
eval(\"\\$r = $n;\");
return $r;
}
//--------------------------------------------------//
function getType($args) {
$argType = array();
foreach($args as $i=>$val) {
$argType[$i][] = $this->getSuffix($val, $i) ;
}
$s = \'\';
if(is_array($argType)){
foreach($argType as $type){
$s .= implode(\'\', $type);
}
return $s;
}
return implode(\'\', $argType);
}
//--------------------------------------------------//
function getSuffix($byValarg, $i) {
if( is_numeric($byValarg) ) {
$type = \'N\';
$this->fargs[\'N\'.$i] = $byValarg;
} elseif( is_array($byValarg) ) {
$type = \'A\';
$this->fargs[\'A\'.$i] = $byValarg;
} elseif( is_object($byValarg) ) {
$type = \'O\';
$this->fargs[\'O\'.$i] = $byValarg;
} elseif( is_resource($byValarg) ) {
$type = \'R\';
$this->fargs[\'R\'.$i] = $byValarg;
} else {
$type = \'S\';
$this->fargs[\'S\'.$i] = $byValarg;
}
return $type;
}
//--------------------------------------------------//
function getArgsName($args){
$r = array();
$ary = array_keys($this->fargs);
foreach( $ary as $k=>$v){
$r[]=\'$this->fargs[\"\'.$v.\'\"]\';
}
return implode(\", \", $r);
}
//--------------------------------------------------//
function __call($name, $args){
$this->fargs = array();
return $this->set(get_class($this), $name, $args);
}
//--------------------------------------------------//
}
class test2 extends overloadable {
function foo_(){
echo \'foo - no args\';
}
function foo_S($s){
echo \"foo - one string $s\";
}
function foo_SS($s1, $s2){
echo \"foo - tow strings $s1, $s2\";
}
function foo_SN($s, $n){
echo \"foo - string and number $s, $n\";
}
function foo_A($ary){
print_r($ary);
}
function foo_AA($ary1, $ary2){
if(is_array($ary1) && is_array($ary2)){
echo \"foo - tow arrays\";
}else{echo 0;}
}
function foo_O($obj){
echo \"foo - \";
print_r($obj);
}
function hi(){
echo \"hi - welcome!\";
}
}
echo \'<pre>\';
$t = new test2();
echo \'<br />foo_: \';
print_r( $t->foo() );
echo \'<br />foo_s: \';
print_r( $t->foo(\'a\') );
echo \'<br />foo_ss: \';
print_r( $t->foo(\'a\', \'b\') );
echo \'<br />foo_sn: \';
print_r( $t->foo(\'a\', 2) );
echo \'<br />foo_snn: \';
print_r( $t->foo(\'s\', 2, 9) );
echo \'<br />foo_a: \';
print_r( $t->foo(array(4,5,6,7)) );
echo \'<br />foo_aa: \';
print_r( $t->foo( array(5,6,7), array(8,9,10) ) );
echo \'<br />foo_o: \';
print_r( $t->foo($t) );
echo \'<br />hi: \';
print_r( $t->hi() );
In PHP 5.6 you can use the splat operator ...
as the last parameter and do away with func_get_args()
and func_num_args()
:
function example(...$args)
{
count($args); // Equivalent to func_num_args()
}
example(1, 2);
example(1, 2, 3, 4, 5, 6, 7);
You can use it to unpack arguments as well:
$args[] = 1;
$args[] = 2;
$args[] = 3;
example(...$args);
Is equivalent to:
example(1, 2, 3);
<?php
class abs
{
public function volume($arg1=null, $arg2=null, $arg3=null)
{
if($arg1 == null && $arg2 == null && $arg3 == null)
{
echo \"function has no arguments. <br>\";
}
else if($arg1 != null && $arg2 != null && $arg3 != null)
{
$volume=$arg1*$arg2*$arg3;
echo \"volume of a cuboid \".$volume .\"<br>\";
}
else if($arg1 != null && $arg2 != null)
{
$area=$arg1*$arg2;
echo \"area of square = \" .$area .\"<br>\";
}
else if($arg1 != null)
{
$volume=$arg1*$arg1*$arg1;
echo \"volume of a cube = \".$volume .\"<br>\";
}
}
}
$obj=new abs();
echo \"For no arguments. <br>\";
$obj->volume();
echo \"For one arguments. <br>\";
$obj->volume(3);
echo \"For two arguments. <br>\";
$obj->volume(3,4);
echo \"For three arguments. <br>\";
$obj->volume(3,4,5);
?>
PHP does not support overloading for now. Hope this will be implemented in the other versions like other programming languages.
Checkout this library, This will allow you to use PHP Overloading in terms of closures.
https://github.com/Sahil-Gulati/Overloading
Sadly there is no overload in PHP as it is done in C#. But i have a little trick. I declare arguments with default null values and check them in a function. That way my function can do different things depending on arguments. Below is simple example:
public function query($queryString, $class = null) //second arg. is optional
{
$query = $this->dbLink->prepare($queryString);
$query->execute();
//if there is second argument method does different thing
if (!is_null($class)) {
$query->setFetchMode(PDO::FETCH_CLASS, $class);
}
return $query->fetchAll();
}
//This loads rows in to array of class
$Result = $this->query($queryString, \"SomeClass\");
//This loads rows as standard arrays
$Result = $this->query($queryString);