PHP
downloads | documentation | faq | getting help | mailing lists | wiki | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

オブジェクトのイタレーション> <オブジェクト インターフェイス
Last updated: Fri, 14 Nov 2008

view this page in

オーバーロード

PHP におけるオーバーロード機能は、 メンバーやメソッドを動的に "作成する" ための手法です。 これらの動的エンティティは、マジックメソッドを用いて処理されます。 マジックメソッドは、クラス内でさまざまなアクションに対して用意することができます。

オーバーロードメソッドが起動するのは、 宣言されていないメンバーやメソッドを操作しようとしたときです。 また、現在のスコープからは アクセス不能な メンバーやメソッドを操作しようとしたときにも起動します。 このセクションでは、これらの (宣言されていない、 あるいは現在のスコープからはアクセス不能な) メンバーやメソッドのことを "アクセス不能メンバー" および "アクセス不能メソッド" と表記することにします。

オーバーロードメソッドは、すべて public で定義しなければなりません。

注意: これらのマジックメソッドの引数は、 参照渡し とすることはできません。

注意: PHP における "オーバーロード" の解釈は、他の多くのオブジェクト指向言語とは異なります。 一般的に「オーバーロード」とは、 「名前は同じだけれども引数の数や型が異なるメソッドを複数用意できる」 という機能のことを指します。

変更履歴

バージョン 説明
5.1.0 __isset()__unset() が追加されました。
5.3.0 __callStatic() が追加されました。 public で、かつ static でない宣言を強制するような警告が追加されました。

メンバーのオーバーロード

void __set ( string $name , mixed $value )
mixed __get ( mixed $name )
bool __isset ( string $name )
void __unset ( string $name )

__set() は、 アクセス不能メンバーへデータを書き込む際に実行されます。

__get() は、 アクセス不能メンバーからデータを読み込む際に使用します。

__isset() は、 isset() あるいは empty() をアクセス不能メンバーに対して実行したときに起動します。

__unset() は、 unset() をアクセス不能メンバーに対して実行したときに起動します。

引数 $name は、 操作しようとしたメンバーの名前です。 __set() メソッドの引数 $value は、 $name に設定しようとした値となります。

メンバーのオーバーロードはオブジェクトのコンテキストでのみ動作します。 これらのマジックメソッドは、静的コンテキストでは起動しません。 したがって、これらのメソッドは static 宣言することはできません。

例1 __get, __set, __isset, __unset を使ったオーバーロードの例

<?php
class MemberTest {
    
/**  オーバーロードされるデータの場所  */
    
private $data = array();

    
/**  宣言されているメンバーにはオーバーロードは起動しません */
    
public $declared 1;

    
/**  クラスの外部からアクセスした場合にのみこれがオーバーロードされます  */
    
private $hidden 2;

    public function 
__set($name$value) {
        echo 
"Setting '$name' to '$value'\n";
        
$this->data[$name] = $value;
    }

    public function 
__get($name) {
        echo 
"Getting '$name'\n";
        if (
array_key_exists($name$this->data)) {
            return 
$this->data[$name];
        }

        
$trace debug_backtrace();
        
trigger_error(
            
'Undefined property via __get(): ' $name .
            
' in ' $trace[0]['file'] .
            
' on line ' $trace[0]['line'],
            
E_USER_NOTICE);
        return 
null;
    }

    
/**  PHP 5.1.0 以降 */
    
public function __isset($name) {
        echo 
"Is '$name' set?\n";
        return isset(
$this->data[$name]);
    }

    
/**  PHP 5.1.0 以降 */
    
public function __unset($name) {
        echo 
"Unsetting '$name'\n";
        unset(
$this->data[$name]);
    }

    
/**  マジックメソッドではありません。単なる例として示しています  */
    
public function getHidden() {
        return 
$this->hidden;
    }
}


echo 
"<pre>\n";

$obj = new MemberTest;

$obj->1;
echo 
$obj->"\n\n";

var_dump(isset($obj->a));
unset(
$obj->a);
var_dump(isset($obj->a));
echo 
"\n";

echo 
$obj->declared "\n\n";

echo 
"Let's experiment with the private property named 'hidden':\n";
echo 
"Privates are visible inside the class, so __get() not used...\n";
echo 
$obj->getHidden() . "\n";
echo 
"Privates not visible outside of class, so __get() is used...\n";
echo 
$obj->hidden "\n";
?>

上の例の出力は以下となります。

Setting 'a' to '1'
Getting 'a'
1

Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)

1

Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'


Notice:  Undefined property via __get(): hidden in <file> on line 70 in <file> on line 29

メソッドのオーバーロード

mixed __call ( string $name , array $arguments )
mixed __callStatic ( string $name , array $arguments )

__call() は、 アクセス不能メソッドをオブジェクトのコンテキストで実行したときに起動します。

__callStatic() は、 アクセス不能メソッドを静的コンテキストで実行したときに起動します。

引数 $name は、 コールしようとしたメソッドの名前です。 引数 $arguments は配列で、メソッド $name に渡そうとしたパラメータが格納されます。

例2 __call および ___callStatic による、インスタンス化されたメソッドのオーバーロードの例

<?php
class MethodTest {
    public function 
__call($name$arguments) {
        
// 注意: $name は大文字小文字を区別します
        
echo "Calling object method '$name' "
             
implode(', '$arguments). "\n";
    }

    
/**  PHP 5.3.0 以降 */
    
public static function __callStatic($name$arguments) {
        
// 注意: $name は大文字小文字を区別します
        
echo "Calling static method '$name' "
             
implode(', '$arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context');  // PHP 5.3.0 以降
?>

上の例の出力は以下となります。

Calling object method 'runTest' in object context
Calling static method 'runTest' in static context


add a note add a note User Contributed Notes
オーバーロード
erick2711 at gmail dot com
14-Nov-2008 07:03
<?php
/***********************************************
 *And here follows a child class which implements a menu based in the 'nodoMenu' class (previous note).
 *
 *[]s
 *
 *erick2711 at gmail dot com
 ************************************************/
class menu extends nodoMenu{
   
private $cssc = array();
   
   
public function __toString(){  //Just to show, replace with something better.
       
$stringMenu = "<pre>\n";$stringMenu .= $this->strPrint();$stringMenu .= "</pre>\n";
        return
$stringMenu;
    }

   
public function __construct($cssn = null){
       
parent::__construct();
        if (isset(
$cssn) && is_array($cssn)){$this->cssc = $cssn;}
       
$this->buildMenu();
    }
   
   
public function buildMenu(){
       
$this->add('server',
                  
'Server',
                  
'server.php');
           
$this->server->add('personalD',
                              
'Personal Data',
                              
'server/personal.php');
           
$this->server->add('personalI',
                              
'Personal Interviews',
                              
'server/personalI.php');
               
$this->server->personalI->add('detailsByIer',
                                             
'Detalis by Interviewer',
                                             
'server/personalI.php?tab=detailsByIer');
       
//(...)
       
return $this;
    }
}

//Testing
$meuMenu = new menu;
echo
$meuMenu;
/***********************************************
 *Will output (to the browser):
 *
 *<pre>
 *1 Server<br>
 *  1.1 Personal Data<br>
 *  1.2 Personal Interviews<br>
 *      1.2.1 Details by Interviewer<br>
 *</pre>
 *
 *Which shows:
 *
 *1 Server
 *  1.1 Personal Data
 *  1.2 Personal Interviews
 *      1.2.1 Details by Interviewer
 ************************************************/
?>
erick2711 at gmail dot com
14-Nov-2008 06:39
<?php
/*
    Here folows a little improvement of the 'strafvollzugsbeamter at gmx dot de' code, allowing each node to hold both 'parameters' and 'child nodes', and differentiate $s->A->B->C ('FOO') from $s->A (same 'FOO', but shouldn't exist) and from $s-A->B (idem).
    This allows the class, using the interesting suggested syntax ($root->dad->child->attribute, in which 'dad's and 'child's names are dynamically generated), to do something actually useful, like implementing a n-tree data structure (a menu, for instance).
    It was tested under PHP 5.2.6 / Windows.
    I know that must there be something better which already do this (probably in the DOM Model classes, or something like), but it was fun to develop this one, for the sake of studying the "magic" methods.
    Its a compressed version of the code (no comments, too short variable names, almost no identation). I had to compress it in order to add the note. If anyone cares about the full version, just email me.
    []s
   
    erick2711 at gmail dot com
*/
class nodoMenu{

   
protected $p  = array();
   
protected $c = array();

   
public function __construct($t = '', $uri = '', $css = null, $n = 0, $i=0){
       
$this->p['t'] = $t;$this->p['uri'] = $uri;$this->p['css'] = $css;$this->p['n'] = $n;$this->p['i'] = $i;$this->p['q'] = 0;return $this;
    }

   
public function add($cn, $ct = '', $cl = '', $css = null){
       
$nc = new nodoMenu($ct, $cl, $css, $this->p['n'] + 1, $this->p['q']);$this->c[$cn] = $nc;$this->p['q'] += 1;return $this->c[$cn];
    }

   
private function isParameter($pn){
        return
array_key_exists($pn, $this->p);
    }
   
   
public function __isset($pn){
        if (
$this->isParameter($pn)){return(!is_null($this->p[$pn]));}
        else{return(
array_key_exists($pn, $this->c));}
    }

   
public function remove($cn){
        if (
array_key_exists($cn, $this->c)){$this->p['q'] -= 1;unset($this->c[$cn]);}
    }

   
public function __unset($pn){
        if (
$this->isParameter($pn)){$this->p[$pn] = null;}
        else{
$this->remove($pn);}
    }

   
public function __set($pn, $v){
       
$r = null;
        if (
$this->isParameter($pn)){$this->p[$pn] = $v;$r = $v;}
        else{if (
array_key_exists($pn, $this->c)){$this->c[$pn] = $v;$r = $this->c[$pn];}
            else{
$r = $this->add($pn);}}   
        return
$r;
    }       

   
public function __get($pn){
       
$v = null;
        if (
$this->isParameter($pn)){$v = $this->p[$pn];}
        else{if (
array_key_exists($pn, $this->c)){$v = $this->c[$pn];}
            else{
$v = $this->add($pn);}}
        return
$v;
    }
   
   
public function hasChilds(){
        return(isset(
$this->c[0]));
    }
   
   
public function child($i){
        return
$this->c[$i];
    }
   
   
public function strPrint($bm = ''){   //Just to show, replace with something better.
       
$m = '';$r = '';$n = $this->p['n'];
        if (
$n > 0){switch($n){case 0:case 1: $qs = 0; break;case 2: $qs = 2; break;case 3: $qs = 6; break;case 4: $qs = 12; break;case 5: $qs = 20; break;case 6: $qs = 30; break;case 7: $qs = 42; break;case 8: $qs = 56; break;}
           
$tab = str_repeat('&nbsp;', $qs);$r .= $tab;
            if (
$bm <> ''){$m = $bm.'.';}
           
$im = $this->p['i'] + 1;$m .= $im;$r .= $m.' ';$r .= $this->p['t']."<br>\n";
        }
        foreach (
$this->c as $child){$r .= $child->strPrint($m);}
        return
$r;
    }
   
   
public function __toString(){
        return
$this->strPrint();
    }
}
?>
Ant P.
30-Aug-2008 06:31
There's nothing wrong with calling these functions as normal functions:

If you end up in a situation where you need to know the return value of your __set function, just write <?php $a = $obj->__set($var, $val); ?> instead of <?php $a = $obj->$var = $val; ?>.
me at ben-xo dot com
11-Aug-2008 05:13
uramihsayibok is correct that PHP diverges from what one would expect based on experiences with other programming languages.

It's a C-ism that the action of assignment, such as $b=$a, is actually a *function* (that has a return value) and in a mathsy, set-theory kind of way, that makes perfect sense. So, when you see $c=$b=$a, you should actually read it as ($c=($b=$a)), as that's where the brackets are grouped. $c is assigned with the return value of ($b=$a), and that return value is the value of the assignment. It's really just 'syntactic sugar' that assignment is written in DEST = SOURCE format (this is known as 'infix notation') rather than =(DEST, SOURCE), which would be valid in some other languages (this is known as 'prefix notation').

PHP does not provide access to the assignment function directly, nor does it allow for operator overriding (if you want to do that sort of magic, try Ruby!) so one can safely assume that the semantics of assignment have been optimised in such a way that __set() is NOT actually overriding assignment, just acting as a pre-commit hook, which is different from how it's implemented in other languages.

Conclusion: __set may appear to override the assignment operator on an object, but BEWARE as that's not what it's actually doing.
strafvollzugsbeamter at gmx dot de
17-Jul-2008 12:27
The following works on my installation (5.2.6 / Windows):
<?php
class G
{
   
private $_p = array();
   
   
public function __isset($k)
    {
        return isset(
$this->_p[$k]);
    }
       
   
public function __get($k)
    {
       
$v = NULL;
        if (
array_key_exists($k, $this->_p))
        {
           
$v = $this->_p[$k];
        }
        else
        {
           
$v = $this->{$k} = $this;
        }
       
        return
$v;
    }
   
   
public function __set($k, $v)
    {
       
$this->_p[$k] = $v;
       
        return
$this;
    }   
}

$s = new G();
$s->A->B->C = 'FOO';
$s->X->Y->Z = array ('BAR');

if (isset(
$s->A->B->C))
{
    print(
$s->A->B->C);
}
else
{
    print(
'A->B->C is NOT set');
}

if (isset(
$s->X->Y->Z))
{
   
print_r($s->X->Y->Z);
}
else
{
    print(
'X->Y->Z is NOT set');
}

// prints: FOOArray ( [0] => BAR )
?>

... have fun and  ...
daveb at spamless dot davebeta dot com
02-Jul-2008 09:06
In reply to uramihsayibok, gmail, com:

The PHP behaviour is the behaviour I would expect.

You are assigning a value to a property: $obj->a=$b works just the same as $a=$b and I would expect both these expressions to evaluate to $b.

The __set() method is used behind the scenes. As a programmer using the class I might not be aware __set() is used unless I originally wrote the class. The return value of __set() is quite rightly ignored.
uramihsayibok, gmail, com
27-May-2008 01:31
Expanding in part on what Hayley Watson said (5 Feb 2008) regarding $a=$b=$c:

My first impression was that <?php $a=$foo->var=$c; ?> would assign $c to $foo->var (by using __set) and the *return value* of __set would be assigned to $a - like what happens in other languages. Perhaps the default (if __set returns void/null) would be $c.

This is not the case. The code above is equivalent to <?php $foo->var=$c; $a=$c; ?>. Regardless of what __set returns, $a will always have the value of $c.

<?php

class Foo {
   
public function __set($name,$value) {
        static
$var; $var=$value;
       
// return "abc"; // comment, uncomment at will
   
}
}

$f=new Foo();
$g=($f->var="value");
echo
$g;
// $g is always "value", even if the return above is uncommented

?>
Anonymous
01-May-2008 12:32
This is a generic implementation to use getter, setter, issetter and unsetter for your own classes.

<?php
abstract
class properties
{
 
public function __get( $property )
  {
    if( !
is_callable( array($this,'get_'.(string)$property) ) )
     
throw new BadPropertyException($this, (string)$property);

    return
call_user_func( array($this,'get_'.(string)$property) );
  }

 
public function __set( $property, $value )
  {
    if( !
is_callable( array($this,'set_'.(string)$property) ) )
     
throw new BadPropertyException($this, (string)$property);

   
call_user_func( array($this,'set_'.(string)$property), $value );
  }
 
 
public function __isset( $property )
  {
    if( !
is_callable( array($this,'isset_'.(string)$property) ) )
     
throw new BadPropertyException($this, (string)$property);

    return
call_user_func( array($this,'isset_'.(string)$property) );
  }

 
public function __unset( $property )
  {
    if( !
is_callable( array($this,'unset_'.(string)$property) ) )
     
throw new BadPropertyException($this, (string)$property);

   
call_user_func( array($this,'unset_'.(string)$property) );
  }
}
?>
nospam michael AT netkey DOT at nospam
01-Apr-2008 10:40
you CAN write into ARRAYS by using __set and __get magic functions.

as has been mentioned before $obj->var['key'] = 'test'; does call the __get method of $obj, and there is no way to find out, if the method has been called for setting purposes.

the solution is quite simple: use __get to return the array by reference. then you can write into it:

<?php
class setter{
 
private $_arr = array();

 
public function __set($name, $value){
   
$this->_arr[$name] = $value;
  }

 
public function &__get($name){
    if (isset(
$this->_arr[$name])){
      return
$this->_arr[$name];
    } else return
null;
  }

}

?>
Matt Creenan
29-Feb-2008 08:04
PHP4 supports using __call but with a twist that I did not see mentioned anywhere on this page.

In 4, you must make the __call method signature with 3 parameters, the 3rd of which is the return value and must be declared by-reference.  Instead of using "return $value;" you would assign the 3rd argument to $value.

Example (both implementations below have the same result when run in the respective PHP versions:

<?php

// Will only work in PHP4
class Foo
{
    function
__call($method_name, $parameters, &$return_value)
    {
       
$return_value = "Method $method_name was called with " . count($parameters) . " parameters";
    }
}

// Will only work in PHP5
class Foo
{
    function
__call($method_name, $parameters)
    {
        return
"Method $method_name was called with " . count($parameters) . " parameters";
    }
}

?>
dave at mozaiq dot org
11-Feb-2008 03:28
Several users have mentioned ways to allow setting of array properties via magic methods. In particular, PHP calls the __get() method instead of the __set() method when you try to do: $obj->prop['offset'] = $val.

The suggestions that I've read below all work, except that they do not allow you make properties read-only. After a bit of struggling, I have found a solution. Essentially, if the property is supposed to be a read-only array, create an new ArrayObject() out of it, then clone it and return the clone.

<?php

public
function __get($var) {
    if(isset(
$this->read_only_props[$var])) {
       
$ret = null;
        if (
is_array($this->read_only_props[$var]))
            return
clone new ArrayObject($this->read_only_props[$var]);
        else if (
is_object($this->read_only_props[$var]))
            return
clone $this->read_only_props[$var];
        else
            return
$this->read_only_props[$var];
    }
    else if (!isset(
$this->writeable_props[$var]))
       
$this->writeable_props[$var] = NULL;
    return
$this->writeable_props[$var];
}

public function __set($var, $val) {
    if (isset(
$this->read_only_props[$var]))
       
throw new Exception('tried to set a read only property on the event object');
    return
$this->writeable_props[$var] = $val;
}
?>

Note that __get() does not explicitly return by reference as many examples have suggested. Also, I have not found a way to detect when __get() is being called for setting purposes, thus my code can not throw an exception when necessary in these cases.
Hayley Watson
06-Feb-2008 05:23
Chained assignments are still right-associative and still work as expected. That is to say, $a = $foo->b = $c is equivalent to $a = ($foo->b = $c) and results in $a being set to the value of $c even if $foo->b is a property handled by __get/__set and even if those methods adjust/validate their arguments (and even if they fail).

In other words, "$a = $b = $c;" and "$a = ($b = $c);" are both equivalent to "$a = $c; $b = $c;" and not to the equally plausible "$b = $c; $a = $b;".

Assignment expressions evaluate to the value that gets assigned - the value that appears on the right-hand side - and what happens to whatever is on the left is treated as a side-effect.
So in the expression $a=$b=$c, $a doesn't care about what does or doesn't happen to $b - all it sees is the *value* of $b=$c, which is just the value of $c. The parentheses make this clearer: in $a=($b=$c) we have $b being assigned the value of $c and $a being assigned the value of ($b=$c).

As already hinted, this is nothing new: it's just made more obvious by __get and __set: $a = $foo->b = $c does NOT involve looking up the value of $foo->b (let alone assigning it to $a), and $foo->__get() isn't called.
timshaw at mail dot NOSPAMusa dot com
29-Jan-2008 09:17
The __get overload method will be called on a declared public member of an object if that member has been unset.

<?php
class c {
 
public $p ;
 
public function __get($name) { return "__get of $name" ; }
}

$c = new c ;
echo
$c->p, "\n" ;    // declared public member value is empty
$c->p = 5 ;
echo
$c->p, "\n" ;    // declared public member value is 5
unset($c->p) ;
echo
$c->p, "\n" ;    // after unset, value is "__get of p"
?>
jj dhoT maturana aht gmail dhot com
25-Jan-2008 03:46
There isn't some way to overload a method when it's called as a reflection method:

<?php

class TestClass {
  function
__call($method, $args) {
    echo
"Method {$method} called with args: " . print_r($args, TRUE);
  }
}

$class = new ReflectionClass("TestClass");
$method = $class->getMethod("myMehtod");

//Fatal error:  Uncaught exception 'ReflectionException' with message 'Method myMethod' does not exist'

?>

Juan.
Bjrn Wikkeling
21-Jan-2008 01:55
In response to Anonymous: 09-Jan-2008 10:45.

PHP 5.3 will include the magic method __callStatic to use for static method calls.

see also:
http://bugs.php.net/bug.php?id=26739
v dot umang at gmail dot com
12-Jan-2008 08:50
If you want to be able to overload a variable from within a class and this is your code:
<?php
class myClass
{
   
private $data;
   
public function __set($var, $val)
    {
       
$this->data[$var] = $val;
    }
   
public function __get($var)
    {
       
$this->data[$var] = $val;
    }
}
?>

There is a problem if you want to call these variables from within the class, as you you want to access data['data'] then you can't say $this->data as it will return the array $data. Therefore a simple solution is to name the array $_data. So in your __get and __set you will say $this->_data ... rather than $this->data. I.E:
<?php
class myClass
{
   
private $_data;
   
public function __set($var, $val)
    {
       
$this->_data[$var] = $val;
    }
   
public function __get($var)
    {
       
$this->_data[$var] = $val;
    }
}
?>

Umang
soldair at NOSPAM gmail.com
10-Jan-2008 08:51
the documentation states a falsehood:
 "All overloading methods must be defined as public."

<?php
class test{
   
#################
    #public use methods#
    #################
   
public static function echoData(){
       
$obj = self::getInstance();
        echo
$obj->find('data');
        return
true;
    }
   
######################
    #only use a single instance#
    ######################
   
private static $instance;
   
private static function getInstance(){
        if(!isset(
self::$instance)){
           
self::$instance = new test;
        }
        return
self::$instance;
    }
   
#################
    #private instantiation#
    #################
   
private $data = array('data'=>'i am data');
   
private function __construct(){}
   
private function __call($nm,$args){
        if(isset(
$this->data[$args[0]])){
            return
$this->data[$args[0]];
        }
        return
null;
    }
}

test::echoData();
?>
--------------OUTPUT---------------
i am data
-----------------------------------

this test was run using PHP Version 5.2.4
Anonymous
09-Jan-2008 07:15
it should be noted that __call will trigger only for method calls on an instantiated object, and cannot be used to 'overload' static methods.  for example:

<?php

class TestClass {
  function
__call($method, $args) {
    echo
"Method {$method} called with args: " . print_r($args, TRUE);
  }
}

// this will succeed
$obj = new TestClass();
$obj->method_doesnt_exist();

// this will not
TestClass::method_doesnt_exist();

?>

It would be useful if the PHP devs would include this in a future release, but in the meantime, just be aware of that pitfall.
egingell at sisna dot com
21-Dec-2007 07:24
The PHP devs aren't going to implement true overloading because: PHP is not strictly typed by any stretch of the imagination (0, "0", null, false, and "" are the same, for example) and unlike Java and C++, you can pass as many values as you want to a function. The extras are ignored unless you fetch them using func_get_arg(int) or func_get_args(), which is often how I "overload" a function/method, and fewer than the declared number of arguments will generate an E_WARNING, which can be suppressed by putting '@' before the function call, but the function will still run as if you had passed null where a value was expected.

<?php
class someClass {
    function
whatever() {
       
$args = func_get_args();
   
       
// public boolean whatever(boolean arg1) in Java
       
if (is_bool($args[0])) {
           
// whatever(true);
           
return $args[0];
   
       
// public int whatever(int arg1, boolean arg2) in Java
       
} elseif(is_int($args[0]) && is_bool($args[1])) {
           
// whatever(1, false)
           
return $args[0];
   
        } else {
           
// public void whatever() in Java
           
echo 'Usage: whatever([int], boolean)';
        }
    }
}
?>

// The Java version:
public class someClass {
    public boolean whatever(boolean arg1) {
        return arg1;
    }
   
    public int whatever(int arg1, boolean arg2) {
        return arg1;
    }
   
    public void whatever() {
        System.out.println("Usage: whatever([int], boolean)");
    }
}
matthijs at yourmediafactory dot com
16-Dec-2007 10:39
While PHP does not support true overloading natively, I have to disagree with those that state this can't be achieved trough __call.

Yes, it's not pretty but it is definately possible to overload a member based on the type of its argument. An example:
<?php
class A {
  
 
public function __call ($member, $arguments) {
    if(
is_object($arguments[0]))
     
$member = $member . 'Object';
    if(
is_array($arguments[0]))
     
$member = $member . 'Array';
   
$this -> $member($arguments);
  }
  
 
private function testArray () {
    echo
"Array.";
  }
  
 
private function testObject () {
    echo
"Object.";
  }
}

class
B {
}

$class = new A;
$class -> test(array()); // echo's 'Array.'
$class -> test(new B); // echo's 'Object.'
?>

Of course, the use of this is questionable (I have never needed it myself, but then again, I only have a very minimalistic C++ & JAVA background). However, using this general principle and optionally building forth on other suggestions a 'form' of overloading is definately possible, provided you have some strict naming conventions in your functions.

It would of course become a LOT easier once PHP'd let you declare the same member several times but with different arguments, since if you combine that with the reflection class 'real' overloading comes into the grasp of a good OO programmer. Lets keep our fingers crossed!
anthony dot parsons at manx dot net
10-Nov-2007 02:27
You can't use __set to set arrays, but if you really want to, you can emulate it yourself:
<?php
class test {
   
public $x = array();
   
public $y = array();
    function
__set($var, $value)
    {
        if (
preg_match('/(.*)\[(.*)\]/', $var, $names) ) {
           
$this->y[$names[1]][$names[2]] = $value;
        }
        else {
           
$this->x[$var] = $value;
        }
    }
}

$z = new test;
$z->variable = 'abc';
$z->{'somearray[key]'} = 'def';

var_dump($z->x);
var_dump($z->y);
?>
php_is_painful at world dot real
19-Oct-2007 06:19
This is a misuse of the term overloading. This article should call this technique "interpreter hooks".
egingell at sisna dot com
12-Oct-2007 09:56
@ zachary dot craig at goebelmediagroup dot com

I do something like that, too. My way might be even more clunky.

<?php

function sum() {
   
$args = func_get_args();
    if (!
count($args)) {
        echo
'You have to supply something to the function.';
    } elseif (
count($args) == 1) {
        return
$args[0];
    } elseif (
count($args) == 2) {
        if (
is_numeric($args[0]) && is_numeric($args[1])) {
            return
$args[0] + $args[1];
        } else {
            return
$args[0] . $args[1];
        }
    }
}

?>

I like the "__call" method, though. You can "declare" multiple functions that don't pollute the namespace. Although, it might be better looking to use this instead of a series of if...elseif... statemenets.

<?php
class myClass {
    function
__call($fName, $fArgs) {
        switch(
$fName) {
            case
'sum':
            if (
count ($fArgs) === 1) {
                return
$fArgs[0];
            } else {
               
$retVal = 0;
                foreach(
$fArgs as $arg ) {
                   
$retVal += $arg;
                }
                return
$retVal;
            }
            break;
            case
'other_method':
            ...
            default:
            die (
'<div><b>Fetal Error:</b> unknown method ' . $fName . ' in ' . __CLASS__ . '.</div>');
        }
// end switch
   
}
}

?>

Side note: if you don't force lower/upper case, you will have case sensitive method names. E.g. $myclass->sum() !== $myclass->Sum().
zachary dot craig at goebelmediagroup dot com
09-Oct-2007 08:43
@egingell at sisna dot com -
  Use of __call makes "overloading" possible also, although somewhat clunky...  i.e.
<?php
class overloadExample
{
  function
__call($fName, $fArgs)
  {
    if (
$fName == 'sum')
    {
      if (
count ($fArgs) === 1)
      {
        return
$fArgs[0];
      }
      else
      {
       
$retVal = 0;
        foreach(
$fArgs as $arg )
        {
         
$retVal += $arg;
        }
        return
$retVal;
      }
    }
  }
}

/*
Simple and trivial I realize, but the point is made.  Now an object of class overloadExample can take
*/
echo $obj->sum(4); // returns 4
echo $obj->sum(4, 5); // returns 9
?>
bgoldschmidt at rapidsoft dot de
28-Sep-2007 11:53
"These methods will only be triggered when your object or inherited object doesn't contain the member or method you're trying to access."
is not quite correct:
they get called when the member you trying to access in not visible:

<?php
class test {

 
public $a;
 
private $b;

  function
__set($name, $value) {
    echo(
"__set called to set $name to $value\n");
   
$this->$name = $value;
  }
}

$t = new test;
$t->a = 'a';
$t->b = 'b';

?>

Outputs:
__set called to set b to b

Be aware that set ist not called for public properties
lokrain at gmail dot com
26-Sep-2007 12:35
Let us look at the following example:

<?php
class objDriver {
   
private $value;

   
public function __construct()
    {
       
$value = 1;
    }

   
public function doSomething($parameterList)
    {
       
//We make actions with the value
   
}
}

class
WantStaticCall {
   
private static $objectList;

   
private function __construct()

   
public static function init()
    {
        
se