<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
 <sect1 xml:id="language.oop5.overloading" xmlns="http://docbook.org/ns/docbook">
  <title>Overloading</title>

  <para>
   Overloading in PHP provides means to dynamically
   <quote>create</quote> properties and methods.
   These dynamic entities are processed via magic methods
   one can establish in a class for various action types.
  </para>

  <para>
   The overloading methods are invoked when interacting with
   properties or methods that have not been declared or are not
   <link linkend="language.oop5.visibility">visible</link> in
   the current scope. The rest of this section will use the terms
   <quote>inaccessible properties</quote> and <quote>inaccessible
   methods</quote> to refer to this combination of declaration
   and visibility.
  </para>

  <para>
   All overloading methods must be defined as <literal>public</literal>.
  </para>

  <note>
   <para>
    None of the arguments of these magic methods can be
    <link linkend="functions.arguments.by-reference">passed by
    reference</link>.
   </para>
  </note>

  <note>
   <para>
    PHP's interpretation of <quote>overloading</quote> is
    different than most object oriented languages. Overloading
    traditionally provides the ability to have multiple methods
    with the same name but different quantities and types of
    arguments.
   </para>
  </note>


  <sect2 xml:id="language.oop5.overloading.changelog">
   &reftitle.changelog;
   <para>
    <informaltable>
     <tgroup cols="2">
      <thead>
       <row>
        <entry>&Version;</entry>
        <entry>&Description;</entry>
       </row>
      </thead>
      <tbody>
       <row>
        <entry>5.3.0</entry>
        <entry>
         Added <function>__callStatic</function>.
         Added warning to enforce public visibility and non-static declaration.
        </entry>
       </row>
       <row>
        <entry>5.1.0</entry>
        <entry>
         Added <function>__isset</function> and <function>__unset</function>.
        </entry>
       </row>
      </tbody>
     </tgroup>
    </informaltable>
   </para>
  </sect2>


  <sect2 xml:id="language.oop5.overloading.members">
   <title>Property overloading</title>

   <methodsynopsis>
    <type>void</type><methodname>__set</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
    <methodparam><type>mixed</type><parameter>value</parameter></methodparam>
   </methodsynopsis>
   <methodsynopsis>
    <type>mixed</type><methodname>__get</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
   </methodsynopsis>
   <methodsynopsis>
    <type>bool</type><methodname>__isset</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
   </methodsynopsis>
   <methodsynopsis>
    <type>void</type><methodname>__unset</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
   </methodsynopsis>

   <para>
    <function>__set</function> is run when writing data to
    inaccessible properties.
   </para>

   <para>
    <function>__get</function> is utilized for reading data from
    inaccessible properties.
   </para>

   <para>
    <function>__isset</function> is triggered by calling
    <function>isset</function> or <function>empty</function>
    on inaccessible properties.
   </para>

   <para>
    <function>__unset</function> is invoked when
    <function>unset</function> is used on inaccessible properties.
   </para>

   <para>
    The <varname>$name</varname> argument is the name of the
    property being interacted with. The <function>__set</function>
    method's <varname>$value</varname> argument specifies the
    value the <varname>$name</varname>'ed property should be set
    to.
   </para>

   <para>
    Property overloading only works in object context. These magic
    methods will not be triggered in static context. Therefore
    these methods should not be declared
    <link linkend="language.oop5.static">static</link>. As of PHP 
    5.3.0, a warning is issued if one of the magic overloading 
    methods is declared <literal>static</literal>.
   </para>

   <note>
    <para>
     The return value of <function>__set</function> is ignored
     because of the way PHP processes the assignment operator.
     Similarly, <function>__get</function> is never called when
     chaining assignments together like this:
     <literal><![CDATA[ $a = $obj->b = 8; ]]></literal>
    </para>
   </note>

   <note>
    <para>
     It is not possible to use overloaded properties in other 
     language constructs than <function>isset</function>. This 
     means if <function>empty</function> is called on an overloaded 
     property, the overloaded method is not called.
    </para>
    <para>
     To workaround that limitation, the overloaded property must 
     be copied into a local variable in the scope and then be 
     handed to <function>empty</function>.
    </para>
   </note>

   <example>
    <title>
     Overloading properties via the <function>__get</function>,
     <function>__set</function>, <function>__isset</function>
     and <function>__unset</function> methods
    </title>
    <programlisting role="php">
<![CDATA[
<?php
class PropertyTest {
    /**  Location for overloaded data.  */
    private $data = array();

    /**  Overloading not used on declared properties.  */
    public $declared = 1;

    /**  Overloading only used on this when accessed outside the class.  */
    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;
    }

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

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

    /**  Not a magic method, just here for example.  */
    public function getHidden() {
        return $this->hidden;
    }
}


echo "<pre>\n";

$obj = new PropertyTest;

$obj->a = 1;
echo $obj->a . "\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";
?>
]]>
    </programlisting>
    &example.outputs;
    <screen role="php">
<![CDATA[
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
]]>
    </screen>

   </example>
  </sect2>

  <sect2 xml:id="language.oop5.overloading.methods">
   <title>Method overloading</title>

   <methodsynopsis>
    <type>mixed</type><methodname>__call</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
    <methodparam><type>array</type><parameter>arguments</parameter></methodparam>
   </methodsynopsis>
   <methodsynopsis>
    <type>mixed</type><methodname>__callStatic</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
    <methodparam><type>array</type><parameter>arguments</parameter></methodparam>
   </methodsynopsis>

   <para>
    <function>__call</function> is triggered when invoking
    inaccessible methods in an object context.
   </para>

   <para>
    <function>__callStatic</function> is triggered when invoking
    inaccessible methods in a static context.
   </para>

   <para>
    The <varname>$name</varname> argument is the name of the
    method being called. The <varname>$arguments</varname>
    argument is an enumerated array containing the parameters
    passed to the <varname>$name</varname>'ed method.
   </para>

   <example>
    <title>
     Overloading methods via the <function>__call</function>
     and <function>__callStatic</function> methods
    </title>
    <programlisting role="php">
  <![CDATA[
<?php
class MethodTest {
    public function __call($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }

    /**  As of PHP 5.3.0  */
    public static function __callStatic($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "Calling static method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

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

MethodTest::runTest('in static context');  // As of PHP 5.3.0
?>
]]>
    </programlisting>
    &example.outputs;
    <screen role="php">
<![CDATA[
Calling object method 'runTest' in object context
Calling static method 'runTest' in static context
]]>
    </screen>
   </example>

  </sect2>

 </sect1>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->