mirror of
https://github.com/sigmasternchen/php-doc-en
synced 2025-03-19 10:28:54 +00:00

still using this, after discussion on the phpdoc list. From now on, manual.ced will need to be found at ~/.phpdoc/manual.ced. git-svn-id: https://svn.php.net/repository/phpdoc/en/trunk@288721 c90b9560-bf6c-de11-be94-00142212c4b1
451 lines
11 KiB
XML
451 lines
11 KiB
XML
<?xml version="1.0" encoding="iso-8859-1"?>
|
|
<!-- $Revision$ -->
|
|
|
|
<appendix xml:id="objaggregation.examples">
|
|
&reftitle.examples;
|
|
<section xml:id="objaggregation.examples.association">
|
|
<title>Object Aggregation examples</title>
|
|
<para>
|
|
An <emphasis>Association</emphasis> is a composition of independently constructed and
|
|
externally visible parts. When we associate classes or objects, each
|
|
one keeps a reference to the ones it is associated with. When we
|
|
associate classes statically, one class will contain a reference to an
|
|
instance of the other class. For example:
|
|
<example>
|
|
<title>Class association</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class MyDateTime {
|
|
|
|
function MyDateTime()
|
|
{
|
|
// empty constructor
|
|
}
|
|
|
|
function now()
|
|
{
|
|
return date("Y-m-d H:i:s");
|
|
}
|
|
}
|
|
|
|
class Report {
|
|
var $_dt;
|
|
// more properties ...
|
|
|
|
function Report()
|
|
{
|
|
$this->_dt = new MyDateTime();
|
|
// initialization code ...
|
|
}
|
|
|
|
function generateReport()
|
|
{
|
|
$dateTime = $this->_dt->now();
|
|
// more code ...
|
|
}
|
|
|
|
// more methods ...
|
|
}
|
|
|
|
$rep = new Report();
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
We can also associate instances at runtime by passing a reference in a
|
|
constructor (or any other method), which allow us to dynamically change
|
|
the association relationship between objects. We will modify the example
|
|
above to illustrate this point:
|
|
<example>
|
|
<title>Object association</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class MyDateTime {
|
|
// same as previous example
|
|
}
|
|
|
|
class MyDateTimePlus {
|
|
var $_format;
|
|
|
|
function MyDateTimePlus($format="Y-m-d H:i:s")
|
|
{
|
|
$this->_format = $format;
|
|
}
|
|
|
|
function now()
|
|
{
|
|
return date($this->_format);
|
|
}
|
|
}
|
|
|
|
class Report {
|
|
var $_dt; // we'll keep the reference to MyDateTime here
|
|
// more properties ...
|
|
|
|
function Report()
|
|
{
|
|
// do some initialization
|
|
}
|
|
|
|
function setMyDateTime(&$dt)
|
|
{
|
|
$this->_dt =& $dt;
|
|
}
|
|
|
|
function generateReport()
|
|
{
|
|
$dateTime = $this->_dt->now();
|
|
// more code ...
|
|
}
|
|
|
|
// more methods ...
|
|
}
|
|
|
|
$rep = new Report();
|
|
$dt = new MyDateTime();
|
|
$dtp = new MyDateTimePlus("l, F j, Y (h:i:s a, T)");
|
|
|
|
// generate report with simple date for web display
|
|
$rep->setMyDateTime($dt);
|
|
echo $rep->generateReport();
|
|
|
|
// later on in the code ...
|
|
|
|
// generate report with fancy date
|
|
$rep->setMyDateTime($dtp);
|
|
$output = $rep->generateReport();
|
|
// save $output in database
|
|
// ... etc ...
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
<emphasis>Aggregation</emphasis>, on the other hand, implies
|
|
encapsulation (hidding) of the
|
|
parts of the composition. We can aggregate classes by using a (static)
|
|
inner class (PHP does not yet support inner classes), in this case the
|
|
aggregated class definition is not accessible, except through the class
|
|
that contains it. The aggregation of instances (object aggregation)
|
|
involves the dynamic creation of subobjects inside an object, in the
|
|
process, expanding the properties and methods of that object.
|
|
</para>
|
|
<para>
|
|
Object aggregation is a natural way of representing a whole-part relationship,
|
|
(for example, molecules are aggregates of atoms), or can be used to
|
|
obtain an effect equivalent to multiple inheritance, without having to
|
|
permanently bind a subclass to two or more parent classes and their
|
|
interfaces. In fact object aggregation can be more flexible, in which we
|
|
can select what methods or properties to "inherit" in the aggregated
|
|
object.
|
|
</para>
|
|
</section>
|
|
<section xml:id="objaggregation.examples2">
|
|
&reftitle.examples;
|
|
<para>
|
|
We define 3 classes, each implementing a different storage method:
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>storage_classes.inc</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
class FileStorage {
|
|
var $data;
|
|
|
|
function FileStorage($data)
|
|
{
|
|
$this->data = $data;
|
|
}
|
|
|
|
function write($name)
|
|
{
|
|
$fp = fopen(name, "w");
|
|
fwrite($fp, $this->data);
|
|
fclose($data);
|
|
}
|
|
}
|
|
|
|
class WDDXStorage {
|
|
var $data;
|
|
var $version = "1.0";
|
|
var $_id; // "private" variable
|
|
|
|
function WDDXStorage($data)
|
|
{
|
|
$this->data = $data;
|
|
$this->_id = $this->_genID();
|
|
}
|
|
|
|
function store()
|
|
{
|
|
if ($this->_id) {
|
|
$pid = wddx_packet_start($this->_id);
|
|
wddx_add_vars($pid, "this->data");
|
|
$packet = wddx_packet_end($pid);
|
|
} else {
|
|
$packet = wddx_serialize_value($this->data);
|
|
}
|
|
$dbh = dba_open("varstore", "w", "gdbm");
|
|
dba_insert(md5(uniqid("", true)), $packet, $dbh);
|
|
dba_close($dbh);
|
|
}
|
|
|
|
// a private method
|
|
function _genID()
|
|
{
|
|
return md5(uniqid(rand(), true));
|
|
}
|
|
}
|
|
|
|
class DBStorage {
|
|
var $data;
|
|
var $dbtype = "mysql";
|
|
|
|
function DBStorage($data)
|
|
{
|
|
$this->data = $data;
|
|
}
|
|
|
|
function save()
|
|
{
|
|
$dbh = mysql_connect();
|
|
mysql_select_db("storage", $dbh);
|
|
$serdata = serialize($this->data);
|
|
mysql_query("insert into vars ('$serdata',now())", $dbh);
|
|
mysql_close($dbh);
|
|
}
|
|
}
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
We then instantiate a couple of objects from the defined classes, and
|
|
perform some aggregations and deaggregations, printing some object information
|
|
along the way:
|
|
</para>
|
|
<para>
|
|
<example>
|
|
<title>test_aggregation.php</title>
|
|
<programlisting role="php">
|
|
<![CDATA[
|
|
<?php
|
|
include "storageclasses.inc";
|
|
|
|
// some utilty functions
|
|
|
|
function p_arr($arr)
|
|
{
|
|
foreach ($arr as $k => $v)
|
|
$out[] = "\t$k => $v";
|
|
return implode("\n", $out);
|
|
}
|
|
|
|
function object_info($obj)
|
|
{
|
|
$out[] = "Class: " . get_class($obj);
|
|
foreach (get_object_vars($obj) as $var=>$val) {
|
|
if (is_array($val)) {
|
|
$out[] = "property: $var (array)\n" . p_arr($val);
|
|
} else {
|
|
$out[] = "property: $var = $val";
|
|
}
|
|
}
|
|
foreach (get_class_methods($obj) as $method) {
|
|
$out[] = "method: $method";
|
|
}
|
|
return implode("\n", $out);
|
|
}
|
|
|
|
|
|
$data = array(M_PI, "kludge != cruft");
|
|
|
|
// we create some basic objects
|
|
$fs = new FileStorage($data);
|
|
$ws = new WDDXStorage($data);
|
|
|
|
// print information on the objects
|
|
echo "\$fs object\n";
|
|
echo object_info($fs) . "\n";
|
|
echo "\n\$ws object\n";
|
|
echo object_info($ws) . "\n";
|
|
|
|
// do some aggregation
|
|
|
|
echo "\nLet's aggregate \$fs to the WDDXStorage class\n";
|
|
aggregate($fs, "WDDXStorage");
|
|
echo "\$fs object\n";
|
|
echo object_info($fs) . "\n";
|
|
|
|
echo "\nNow let us aggregate it to the DBStorage class\n";
|
|
aggregate($fs, "DBStorage");
|
|
echo "\$fs object\n";
|
|
echo object_info($fs) . "\n";
|
|
|
|
echo "\nAnd finally deaggregate WDDXStorage\n";
|
|
deaggregate($fs, "WDDXStorage");
|
|
echo "\$fs object\n";
|
|
echo object_info($fs) . "\n";
|
|
|
|
?>
|
|
]]>
|
|
</programlisting>
|
|
</example>
|
|
</para>
|
|
<para>
|
|
We will now consider the output to understand some of the side-effects
|
|
and limitation of object aggregation in PHP.
|
|
First, the newly created <varname>$fs</varname> and <varname>$ws</varname>
|
|
objects give the expected output (according to their respective class
|
|
declaration). Note that for the purposes of object aggregation,
|
|
<emphasis>private elements of a class/object begin with an underscore
|
|
character ("_")</emphasis>, even though there is not real distinction between
|
|
public and private class/object elements in PHP.
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
$fs object
|
|
Class: filestorage
|
|
property: data (array)
|
|
0 => 3.1415926535898
|
|
1 => kludge != cruft
|
|
method: filestorage
|
|
method: write
|
|
|
|
$ws object
|
|
Class: wddxstorage
|
|
property: data (array)
|
|
0 => 3.1415926535898
|
|
1 => kludge != cruft
|
|
property: version = 1.0
|
|
property: _id = ID::9bb2b640764d4370eb04808af8b076a5
|
|
method: wddxstorage
|
|
method: store
|
|
method: _genid
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
We then aggregate <varname>$fs</varname> with the
|
|
<classname>WDDXStorage</classname> class, and print out the object
|
|
information. We can see now that even though nominally the
|
|
<varname>$fs</varname> object is still of
|
|
<classname>FileStorage</classname>, it now has the property
|
|
<varname>$version</varname>, and the method <function>store</function>,
|
|
both defined in <classname>WDDXStorage</classname>. One important thing
|
|
to note is that it has not aggregated the private elements defined in
|
|
the class, which are present in the <varname>$ws</varname> object. Also
|
|
absent is the constructor from <classname>WDDXStorage</classname>, which
|
|
will not be logical to aggegate.
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
Let's aggregate $fs to the WDDXStorage class
|
|
$fs object
|
|
Class: filestorage
|
|
property: data (array)
|
|
0 => 3.1415926535898
|
|
1 => kludge != cruft
|
|
property: version = 1.0
|
|
method: filestorage
|
|
method: write
|
|
method: store
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
The process of aggregation is cumulative, so when we aggregate
|
|
<varname>$fs</varname> with the class <classname>DBStorage</classname>,
|
|
generating an object that can use the storage methods of all the
|
|
defined classes.
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
Now let us aggregate it to the DBStorage class
|
|
$fs object
|
|
Class: filestorage
|
|
property: data (array)
|
|
0 => 3.1415926535898
|
|
1 => kludge != cruft
|
|
property: version = 1.0
|
|
property: dbtype = mysql
|
|
method: filestorage
|
|
method: write
|
|
method: store
|
|
method: save
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
Finally, the same way we aggregated properties and methods dynamically,
|
|
we can also deaggregate them from the object. So, if we deaggregate the
|
|
class <classname>WDDXStorage</classname> from <varname>$fs</varname>, we
|
|
will obtain:
|
|
</para>
|
|
<para>
|
|
<informalexample>
|
|
<programlisting>
|
|
<![CDATA[
|
|
And deaggregate the WDDXStorage methods and properties
|
|
$fs object
|
|
Class: filestorage
|
|
property: data (array)
|
|
0 => 3.1415926535898
|
|
1 => kludge != cruft
|
|
property: dbtype = mysql
|
|
method: filestorage
|
|
method: write
|
|
method: save
|
|
]]>
|
|
</programlisting>
|
|
</informalexample>
|
|
</para>
|
|
<para>
|
|
One point that we have not mentioned above, is that the process of
|
|
aggregation will not override existing properties or methods in the
|
|
objects. For example, the class <classname>FileStorage</classname> defines a
|
|
<varname>$data</varname> property, and the class
|
|
<classname>WDDXStorage</classname> also defines a similar property
|
|
which will not override the one in the object acquired during
|
|
instantiation from the class <classname>FileStorage</classname>.
|
|
</para>
|
|
</section>
|
|
</appendix>
|
|
|
|
<!-- 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
|
|
-->
|
|
|