Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] - نسخه متنی

David Lane, Hugh E. Williams

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








4.1 Classes and Objects


The basic idea of object-oriented programming is to bind data and
functions in convenient containers called
objects

.
For instance, in Chapter 7
we'll show you how to standardize the look of your
own web pages through an object called a template. Your PHP code can
refer to this object through a variable; we'll
assume here you've decided to call the variable
$template. All the complex implementation of
templates is hidden: you just load in the proper package and issue a
PHP statement such as:

$template = new HTML_Template_IT("./templates");

As the statement suggests, you've just created a new
object. The object is called $template and is
built by the HTML_Template_IT packagea
package whose code you don't need to know anything
about. Once you have a template object, you can access the
functionality provided by the HTML_Template_IT
package.

After various manipulations of the $template
object, you can insert the results into your web page through the PHP
statement:

$template->show( );

The syntax of this statement is worth examining. As the parentheses
indicate, show( ) is a function. However the
-> operator associates show(
)
with the object variable $template.
When the function show( ) is called, it uses the
data that is held by the $template object to
calculate a result: put another way, show( ) is
called on the $template
object.

The functions that you can call depend on the support provided by the
packagethe show( ) function is provided
by the HTML_Template_IT package and can be
called on HTML_Template_IT objects such as
$template. In traditional object-oriented
parlance, show( ) is called a
method

or member
function


of the
HTML_Template_IT object.

HTML_Template_IT is called a
class

because you can use it to create many similar template objects. Each
time you issue a new statement you are said to
create an instance of the class. Thus, the
$template object is an instance of the
HTML_Template_IT class.

We've shown how to use objects created by other
packages. However, to understand objects better,
it's time to define a class of our own. Example 4-1 shows a simple class invented for the purposes
of this chapter that's called
UnitCounter. The
UnitCounter class provides two trivial features:
we can use a UnitCounter object to keep a count
of things, and to calculate the total weight of the things we have
counted. Later in this chapter, and in Chapter 14 we use the UnitCounter
class, together with other classes, to develop a simple freight-cost
calculator.

Example 4-1 shows how the class
UnitCounter is defined using the
class keyword. The
UnitCounter class defines two member
variables


$units and
$weightPerUnit, and two functions add(
)
and totalWeight( ). Collectively,
the variables and the functions are members of
the class UnitCounter.

Example 4-1. Definition of the user-defined class UnitCounter


<?php
// Definition of the class UnitCounter
//
class UnitCounter
{
// Member variables
var $units = 0;
var $weightPerUnit = 1.0;
// Add $n to the total number of units, default $n to 1
function add($n = 1)
{
$this->units = $this->units + $n;
}
// Member function that calculates the total weight
function totalWeight( )
{
return $this->units * $this->weightPerUnit;
}
}
?>

The class definition defines how data and functionality are actually
bound togethermember variables and functions take their
meaning from the class of which they're a part. The
class definition shown in Example 4-1 does not
actually run any code or produce any output. Instead a class
definition creates a new data type that can be used in a PHP script.
In practice, you might save the class definition in an include file,
and include that file into any script that makes use of the class.

To use the member variables and functions defined in a class, an
instance

of the class or object needs to be created. Like
other data types such as integers, strings, or arrays, objects can be
assigned to variables. However, unlike other types, objects are
created using the new operator. An object of class
UnitCounter can be created and assigned to a
variable as follows:

// Create a new UnitCounter object
$bottles = new UnitCounter;

Unlike variable names, class names in PHP are not case sensitive.
While we start all our class names with an uppercase letter,
UnitCounter, unitcounter,
and UNITCOUNTER all refer to the same class.

Once a new UnitCounter object is created and
assigned to the $bottles variable, the member
variables and functions can be used. Members of the object, both
variables and functions, are accessed using the
-> operator. The $units
member variable can be accessed as
$bottles->units and used like any other
variable:

// set the counter to 2 dozen bottles
$bottles->units = 24;
// prints "There are 24 units"
print "There are {$bottles->units} units";

To include the value of an object's member variables
in a double-quoted string literal, the braces syntax is used. String
literals and the braces syntax are discussed in Chapter 2.

The add( ) member function can be called to
operate on the $bottles variable by calling
$bottles->add( ). The following fragment
increases the value of $bottles->units by 3:

// Add three bottles
$bottles->add(3);
// prints "There are 27 units"
print "There are {$bottles->units} units";

Many objects of the same class can be created. For example, you can
use the following fragment to create two
UnitCounter objects and assign them to two
variables:

// Create two UnitCounter objects
$books = new UnitCounter;
$cds = new UnitCounter;
// Add some units
$books->add(7);
$cds->add(10);
// prints "7 books and 10 CDs"
print "{$books->units} books and {$cds->units} CDs";

Both the $books and $cd
variables reference UnitCounter objects, but
each object is independent of the other.


4.1.1 Member Variables




Member variables are available in PHP4
and PHP5.

Member variables are declared as part of a class definition using the
var keyword. Member variables can also be defined
with the private and protected
keywords as we describe later in the chapter. Member variables hold
the data that is stored in an object.

The initial value assigned to a member variable can be defined in the
class definition. The UnitCounter class defined
in Example 4-1 sets initial values for both member
variables:

var $units = 0;
var $weightPerUnit = 1.0;

The var keyword is required to indicate that
$units and $weightPerUnit are
class member variables. When a new UnitCounter
object is created, the initial values of $units
and $weightPerUnit are set to 0 and 1.0
respectively. If a default value is not provided in the class
definition, then the member variable is not set to any value.

You don't have to explicitly declare member
variables as we have in Example 4-1. However, we recommend
that you always declare them and set an initial value because it
makes the initial state of the variables obvious to users of your
code.


4.1.2 Member Functions





Member functions are available in PHP4
and PHP5.

Member functions are defined as part of the class
definitionthe UnitCounter class defined
in Example 4-1 includes two member functions
add( ) and totalWeight( ).
Both these functions access the member variables of the object with
the special variable $this. The variable
$this is special because PHP uses it as a
placeholder until a real object is created. When a member function is
run, the value of $this is substituted with the
actual object that the function is called on. Consider the
implementation of the add( ) member function of
UnitCounter from Example 4-1:

// Add $n to the total number of units, default $n to 1 if
// no parameters are passed to add( )
function add($n = 1)
{
$this->units = $this->units + $n;
}

The function adds the value of the parameter $n to
the member variable $this->units. If no
parameter is passed, $n defaults to 1. When the
add( ) function is called on the
$bottles object in the following example,

// Create a new UnitCounter object
$bottles = new UnitCounter;
// Call the add( ) function
$bottles->add(3);

the placeholder $this in the add(
) function acts as the object $bottles.

The totalWeight( ) member function also accesses
member variables with the $this placeholder: the
function returns the total weight by multiplying the value of the
member variables $this->units and
$this->weightPerUnit.

// Create a new UnitCounter object
$bricks = new UnitCounter;
$bricks->add(15);
// Prints 15 - 15 units at 1 Kg each
print $bricks->totalWeight( );

PHP5 allows the result of a member function to be included into a
string literal using the braces syntax. The following fragment shows
how, and shows an alternative that can be used with PHP4:

// This line only works for PHP5
print "total weight = {$bottles->totalWeight( )} kg";
// This works for both PHP4 and PHP5
print "total weight = " . $bottles->totalWeight( ) . " kg";


4.1.3 Using include Files for Class Definitions





By placing the definition
in Example 4-1 into a filefor example
UnitCounter.incyou can include or require
the UnitCounter class in other scripts. Example 4-2 uses the require directive
to include the UnitCounter class definition.

Example 4-2. Using the UnitCounter class


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Using UnitCounter</title>
</head>
<body>
<?php
require "UnitCounter.inc";
// Create a new UnitCounter object
$bottles = new UnitCounter;
// set the counter to 2 dozen bottles
$bottles->units = 24;
// Add a single bottle
$bottles->add( );
// Add three more
$bottles->add(3);
// Show the total units and weight
print "There are {$bottles->units} units, ";
print "total weight = " . $bottles->totalWeight( ) . " kg";
// Change the default weight per unit and show the new total weight
$bottles-> weightPerUnit = 1.2;
print "<br>Correct total weight = " . $bottles->totalWeight( ) . " kg";
?>
</body>
</html>

We introduce the include and require directives in Chapter 2, and further examples are given in Chapter 6 and Chapter 16 where
we develop practical libraries for our case study, Hugh and
Dave's Online Wines.


4.1.4 Constructors




Two
different methods of defining constructors are available in PHP5, and
one method is available in PHP4.

As discussed previously, when an object is created from the
UnitCounter class defined in Example 4-1, PHP will initialize the member variables
$units and $weightPerUnit to 0
and 1.0 respectively. If you needed to set the weight per unit to
another value, you can set the value directly after creating the
object. For example:

// Create a new UnitCounter object
$bottles = new UnitCounter;
// Set the true weight of a bottle
$bottles->weightPerUnit = 1.2;

However, a better solution is to define a

constructor
function
that correctly sets up the initial state of a new
object before it is used. If a constructor is defined, you
don't have to do anything in your code because PHP
automatically calls it when a new object is created.

PHP5 allows you to declare a constructor method by including the
member function _ _construct( ) in the class
definitionthe function name _ _construct(
)
is reserved for this purpose (the characters preceding
the word construct are two consecutive
underscores). Example 4-3 shows a modified
UnitCounter class with a constructor that
automatically sets the weight per unit.

Example 4-3. Defining a constructor for the class UnitCounter


<?php
class UnitCounter
{
var $units;
var $weightPerUnit;
function add($n = 1)
{
$this->units = $this->units + $n;
}
function totalWeight( )
{
return $this->units * $this->weightPerUnit;
}
// Constructor function that initializes the member variables
function _ _construct($unitWeight = 1.0)
{
$this->weightPerUnit = $unitWeight;
$this->units = 0;
}
}
?>

The class definition works the same as the definition shown in Example 4-1. However, the initial values for
$units and $weightPerUnit are
no longer defined with the variable declaration instead they are set
in the _ _construct( ) member function. A new
UnitCounter object that uses the class defined
in Example 4-3 is created as follows:

// Create a UnitCounter where each unit is 1.2 kg -- the
// weight of a full wine bottle.
$bottles = new UnitCounter(1.2);

When the object is created, PHP automatically calls the _
_construct( )
with the parameters supplied after the class
name. So, in this example, 1.2 is passed as a value to the
_ _construct( ) method and the
$bottles->weightPerUnit variable is set to 1.2.
UnitCounter objects can still be created without
passing a value to the constructor as the parameter variable
$unitWeight defaults to 1.0.

You can also define a constructor method by including a function with
the same name as the class. This is the only way constructors can be
defined in PHP 4, but it can also be used as an alternative in PHP5.
For example, using this technique, the _ _construct(
)
function in Example 4-3 could be
replaced with:

function UnitCounter($weightPerUnit = 1)
{
$this->weightPerUnit = $weightPerUnit;
$this->units = 0;
}

Using the _ _construct( ) function makes
managing large projects easier, because it allows classes to be
moved, renamed, and reused in a class hierarchy without changing the
internals of the class definition. We discuss class hierarchies in
Chapter 14.


4.1.5 Destructors





Destructors
are available in PHP5.

If it exists, a constructor function is called when an object is
created. Similarly, if it exists, a destructor function
is called when an object is destroyed. Like other PHP
variables, objects are destroyed when they go out of scope or when
explicitly destroyed with a call to the unset( )
function. We discuss variable scope in Chapter 2.

A destructor function is defined by including the function
_ _destruct( ) in the class definition (again,
the prefix before the keyword destruct is two
consecutive underscore characters, and _ _destruct(
)
is a reserved function name). _ _destruct(
)
can't be defined to take any parameters
(unlike the _ _construct( ) function). However,
the _ _destruct( ) function does have access to
the member variables of the object that is being destroyedPHP
calls _ _destruct( ) just before the member
variables are destroyed.

Destructor functions are useful when you want to perform some
housekeeping tasks when a process has ended. For example, you might
want to gracefully close down a connection to a DBMS or save user
preferences to a file. Destructors can also be used as a debugging
tool when developing object-oriented applications. For example, by
adding the following _ _destruct( ) function to
the UnitCounter defined in Example 4-3, you can track when objects are destroyed:

    // Destructor function called just before a UnitCounter object
// is destroyed
function _ _destruct( )
{
print "UnitCounter out of scope. Units: {$this->units}";
}

We give another example of _ _destruct( ) later
in the chapter in Section 4.1.8.


4.1.6 Private Members Variables





Private member variables are
available in PHP5.

When using the UnitCounter class defined
previously in Example 4-3, a script can use the
member variables $units and
$weightPerUnit directly, the
UnitCounter class doesn't
implement any safeguards that prevent inconsistent values being
assigned. For example, consider the following fragment that
erroneously sets the number of units to a fractional value and the
weight per unit to a negative number:

// Construct a new UnitCounter object
$b = new UnitCounter;
// Set some values
$b->units = 7.3;
$b->weightPerUnit = -5.5;
$b->add(10);
// Show the total units and weight
print "There are {$b->units} units, ";
print "total weight = {$b->totalWeight( )} kg";

This prints:

There are 7.3 units, total weight = -40.15 kg

In PHP5, a better solution is to define member variables as
private and provide member functions that
control how the variables are used. Example 4-4
shows both the $units and
$weightPerUnit member variables defined as
private.

Example 4-4. Private member variables


<?php
class UnitCounter
{
private $units = 0;
private $weightPerUnit = 1.0;
function numberOfUnits( )
{
return $this->units;
}
function add($n = 1)
{
if (is_int($n) && $n > 0)
$this->units = $this->units + $n;
}
function totalWeight( )
{
return $this->units * $this->weightPerUnit;
}
function _ _construct($unitWeight)
{
$this->weightPerUnit = abs((float)$unitWeight);
$this->units = 0;
}
}
?>

When a UnitCounter object is created using the
class defined in Example 4-4, the
$units and $weightPerUnit
member variables can only be accessed by code defined in the class.
Attempts to access the private member variables cause an error:

// Construct a UnitCounter object as defined in Example 4-4
$b = new UnitCounter(1.1);
// These lines cause an error
$b->units = 7.3;
$b->weightPerUnit = -5.5;

The member function numberOfUnits( ) provides
access to the value of $units, and the member
function add( ) has been improved so only
positive integers can be added to the count value. We have also
improved the _ _construct( ) function to ensure
that $weightPerUnit is only set with a positive
value.

Providing member functions that control how member variables are used
is good object-oriented practice. However, without making member
variables private, there is little point in providing such
safeguards, because users can directly access and modify the member
variable values.


4.1.7 Private Member Functions






Private member functions are
available in PHP5.

Member functions can also be defined as private to hide the
implementation of a class. This allows the implementation of a class
to be modified, or replaced without any effect on the scripts that
use the class. Example 4-5 demonstrates how the
class FreightCalculator hides the internal
methods used by the publicly-accessible member function
totalFreight( ). The method calculates a freight
cost using two private functions perCaseTotal( )
and perKgTotal( ).

Example 4-5. Private member functions


class FreightCalculator
{
private $numberOfCases;
private $totalWeight;
function totalFreight( )
{
return $this->perCaseTotal( ) + $this->perKgTotal( );
}
private function perCaseTotal( )
{
return $this->numberOfCases * 1.00;
}
private function perKgTotal( )
{
return $this->totalWeight * 0.10;
}
function _ _construct($numberOfCases, $totalWeight)
{
$this->numberOfCases = $numberOfCases;
$this->totalWeight = $totalWeight;
}
}

Like private member variables, private functions can only be accessed
from within the class that defines them. The following example causes
an error:

// Construct a FreightCalculator object as defined in Example 4-5
$f = new FreightCalculator(10, 150);
// These lines cause an error
print $f->perCaseTotal( );
print $f->perKgTotal( );
// This is OK -- prints "25"
print $f->totalFreight( );


4.1.8 Static Member Variables





Static member variables are available
in PHP5.

PHP allows member variables and functions to be declared as
static using the static
keyword. As we have shown in our examples so far, normal member
variables are independent from object to object. In contrast, static
member variables are shared across all instances of a class. This
allows you to share values between several instances of a class
without declaring a global variable that's
accessible throughout your application.

Example 4-6 defines the class
Donation that records a donor name and donation
amount in the private member variables $name and
$amount. The class keeps track of the total amount
donated, and the total number of donations using two static variables
$totalDonated and
$numberOfDonors. The values of these two variables
are accessible to all instances of the class, and each instance can
update and read the values. Static member variables are accessed
using a class reference
rather than the
-> operator. In Example 4-6,
the static variables $totalDonated and
$numberOfDonors are prefixed by the class
reference Donation:: when they are used.

Example 4-6. Static member variables


<?php
class Donation
{
private $name;
private $amount;
static $totalDonated = 0;
static $numberOfDonors = 0;
function info( )
{
$share = 100 * $this->amount / Donation::$totalDonated;
return "{$this->name} donated {$this->amount} ({$share}%)";
}
function _ _construct($nameOfDonor, $donation)
{
$this->name = $nameOfDonor;
$this->amount = $donation;
Donation::$totalDonated = Donation::$totalDonated + $donation;
Donation::$numberOfDonors++;
}
function _ _destruct( )
{
Donation::$totalDonated = Donation::$totalDonated - $donation;
Donation::$numberOfDonors--;
}
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Using Donation</title>
</head>
<body>
<pre>
<?php
$donors = array(
new Donation("Nicholas", 85.00),
new Donation("Matt", 50.00),
new Donation("Emily", 90.00),
new Donation("Sally", 65.00));
foreach ($donors as $donor)
print $donor->info( ) . "\n";
$total = Donation::$totalDonated;
$count = Donation::$numberOfDonors;
print "Total Donations = {$total}\n";
print "Number of Donors = {$count}\n";
?>
</pre>
</body>
</html>

The static variables $totalDonated and
$numberOfDonors are updated in the _
_construct( )
function: the $donation
amount is added to the value of $totalDonated, and
$numberOfDonors is incremented. We have also
provided a _ _destruct( ) function that
decreases the value of $totalDonated and
$numberOfDonors when a
Donation object is destroyed.

After the class Donation is defined, Example 4-6 creates an array of donation objects, then
prints the total donated and the total number of donations:

$total = Donation::$totalDonated;
$count = Donation::$numberOfDonors;
print "Total Donations = {$total}\n";
print "Number of Donors = {$count}\n";

The previous fragment demonstrates that static variables can be
accessed from outside the class definition with the
Donation:: class reference prefix. You
don't access static member variable with the
-> operator (which is used with instances of a
class) because they are not associated with any particular object.

A foreach loop is used to print information about
each donation by calling the member function info(
)
for each Donation object. The
info( ) member function returns a string that
contains the donor name, amount, and the percentage of the total that
the donor has contributed. The percentage is calculated by dividing
the value stored for the instance in
$this->amount by the static total value
Donation::$totalDonated.

The output of Example 4-6 is as follows:

Nicholas donated 85 (29.3103448276%)
Matt donated 50 (17.2413793103%)
Emily donated 90 (31.0344827586%)
Sally donated 65 (22.4137931034%)
Total Donations = 290
Number of Donors = 4

Unlike other member variables, you don't need to
create an object to use static member variables. As long as the
script has access to the class definition, static variables are
available using the class reference as shown in the following
fragment:




// provide access to the Donation class definition
require "example.4-6.php";
// Now set the static total
Donation::$totalDonated = 124;
Donation::$numberOfDonors = 5;


4.1.9 Static Member Functions






Static member functions are
available in PHP5.

Static member functions are declared using the
static keyword, and like static member variables,
aren't accessed via objects but operate for the
whole class and are accessed using a class reference. We can modify
Example 4-6 to provide access to the static member
variables using static member functions:

private static $totalDonated = 0;
private static $numberOfDonors = 0;
static function total( )
{
return Donation::$totalDonated;
}
static function numberOfDonors( )
{
return Donation::$numberOfDonors;
}

Code that uses the modified Donation class can
then access the $totalDonated and
$numberOfDonors values by calling the static
functions Donation::total( ) and
Donation::numberOfDonors( ) respectively.

Static functions can only operate on static member variables and
can't operate on objects, and therefore the function
body can't refer to the placeholder variable
$this.

Like static member variables, you can access static functions without
actually creating an object instance. Indeed we could have
implemented the static member variables defined in Example 4-6, and the static member functions
total( ) and numberOfDonors(
)
described earlier using global variables and normal
user-defined functions. Defining member variables and functions as
static provides a way of grouping related functionality together in
class definitions, promoting a modular approach to code development.


4.1.10 Cloning Objects





Objects
can optionally be cloned in PHP5, and are always cloned in PHP4. We
explain how this works in this section.

4.1.10.1 Cloning in PHP5


When a new object is created, PHP5 returns a reference to the object
rather than the object itself. A variable assigned with an object is
actually a reference to the object. This is a significant change from
PHP4 where objects are assigned directly to variables. Copying an
object variable in PHP5 simply creates a second reference to the same
object. This behavior can be seen in the following fragment of code
that creates a new UnitCounter object, as
defined earlier in Example 4-1:

// Create a UnitCounter object
$a = new UnitCounter( );
$a->add(5);
$b = $a;
$b->add(5);
// prints "Number of units = 10";
print "Number of units = {$a->units}";

The _ _clone( ) method is available if you want
to create an independent copy of an object. PHP5 provides a default
_ _clone( ) function that creates a new,
identical object by copying each member variable. Consider the
following fragment:

// Create a UnitCounter object
$a = new UnitCounter( );
$a->add(5);
$b = $a->_ _clone( );
$b->add(5);
// prints "Number of units = 5"
print "Number of units = {$a->units}";
// prints "Number of units = 10"
print "Number of units = {$b->units}";

The code creates an object $a, and adds five units
to it using $a->add(5) to give a total of 5
units in object $a. Then, $a is
cloned and the result is assigned to a new object
$b. Five units are then added to the new object
$b, to give a total of 10 units in
$b. Printing out the number of units for the
original object $a outputs 5, and printing the
number of units for $b outputs 10.

You can control how an object is copied by including a custom
_ _clone( ) function in a class definition. If
you wanted cloned UnitCounter objects to
maintain the $weightPerUnit value, but to reset
the $units value to zero, you can include the
following function in the class definition:

function _  _clone( )
{
$this->weightPerUnit = $that->weightPerUnit;
$this->units = 0;
}

The original, source object is referred to in the _ _clone(
)
function using the special place-holder variable
$that, and the variable $this
is used to reference the new, cloned object.

4.1.10.2 Cloning in PHP4


Rather than use references by default, new objects created with PHP4
can be assigned directly to variables. When an object variable is
copied, PHP4 automatically clones the object. For example, consider
the following PHP4 fragment:

// Create a UnitCounter object
$a = new UnitCounter( );
$a->add(5);
$b = $a;
$b->add(5);
// prints "Number of units = 5"
print "Number of units = {$a->units}";
// prints "Number of units = 10"
print "Number of units = {$b->units}";

The variable $b is a clone or copy of
$a, and so modifying $b does
not affect $a.

If you don't want to clone an object, use the
reference assignment =& to copy a reference.
The following shows how $b is assigned as a
reference to UnitCounter object assigned to
$a:

// Create a UnitCounter object
$a = new UnitCounter( );
$a->add(5);
$b =& $a;
$b->add(5);
// prints "Number of units = 10"
print "Number of units = {$a->units}";
// prints "Number of units = 10"
print "Number of units = {$b->units}";

We discuss variable references and the reference assignment operator
=& in Chapter 2.



/ 176