What is/is not considered to be good OO programming

284 views
Skip to first unread message

Tony Marston

unread,
Aug 7, 2003, 7:45:59 AM8/7/03
to
On my website I have an article
http://www.tonymarston.net/php-mysql/databaseobjects.html which
describes an abstract class I have written to control all access to my
databases. Someone who is supposed to be a respected member of the PHP
community has informed me that my class breaks the rules of OO
programming and is therefore unworthy of serious consideration. To be
specific he complained that my class contains the following
variables:-

$rows_per_page (to set the page size)
$page_no (to request a particular page number)
$lastpage (returns the highest possible page number)

which he considers to related to formatting rather than the data
itself, and as such is *bad* programming.

I personally think that he is talking out of the wrong end of his
alimentary canal for the following reasons:-

1) Those variables are not for *formatting*, they are for *data
selection*. When my presentation layer communicates with a database
object it is basically saying "get me the data that satisfies this
selection criteria" part of which is "based on a page size of
$row_per_page get me the records for page $page_no, and tell me the
highest possible page available".

2) Despite me asking him what he considers to be the *right* way of
doing things he has failed to respond, probably because he doesn't
know the answer.

3) There is nothing in any OOP literature I have read that says what I
am doing is wrong, there it is not wrong.

4) The language allows me to do it, therefore it cannot be wrong.

5) It is simple and it works, therefore it cannot be all that bad.

Do you people out there in PHP-land have any opinions on this matter?
Is this critocism justified or not?

Tony Marston
http://www.tonymarston.net/

Martin Wickman

unread,
Aug 7, 2003, 8:16:55 AM8/7/03
to
In article <7588a50f.03080...@posting.google.com>, Tony Marston wrote:

> On my website I have an article
> http://www.tonymarston.net/php-mysql/databaseobjects.html which
> describes an abstract class I have written to control all access to
> my databases. Someone who is supposed to be a respected member of
> the PHP community has informed me that my class breaks the rules of
> OO programming and is therefore unworthy of serious consideration.

> he considers [the code to be ] related to formatting rather than the


> data itself, and as such is *bad* programming.

Everyone thinks they know what correct OO is, unfortunately I am the
only one that truly knows it. So here is the correct response:

Gimme a break. There is _nothing_ in OO which says that you should not
mix presentation code with logic code. OO deals with encapsulation and
dependencies, not implementation. As long concerns are separated "well
enough", there is no reason to worry.

Otoh, there is general consensus regarding GUI-apps which says you
should not mix presentation with logic. But that is more like common
knowledge than OO.

> 2) Despite me asking him what he considers to be the *right* way of
> doing things he has failed to respond, probably because he doesn't
> know the answer.

Probably.

> 4) The language allows me to do it, therefore it cannot be wrong.

Yup, otherwise you'd get a syntax error...

> 5) It is simple and it works, therefore it cannot be all that bad.

Yes, that is the single most important point to make:

KISS -- keep it simple, stupid.

Anything else will just make it a lot harder to keep up when the
system demands (inevitable) change.

> Do you people out there in PHP-land have any opinions on this matter?
> Is this critocism justified or not?

I think the OO features in PHP3/4 sucks. I mostly use PHPs object as
simple wrappers for variables (structs) and keep 95% of all
programming functional.

Dave Martin

unread,
Aug 7, 2003, 8:21:33 AM8/7/03
to
In article <7588a50f.03080...@posting.google.com>,
to...@marston-home.demon.co.uk says...

> http://www.tonymarston.net/php-mysql/databaseobjects.html which
> describes an abstract class I have written to control all access to my
> databases.

Nicely done Tony.

> 1) Those variables are not for *formatting*, they are for *data
> selection*. When my presentation layer communicates with a database
> object it is basically saying "get me the data that satisfies this
> selection criteria" part of which is "based on a page size of
> $row_per_page get me the records for page $page_no, and tell me the
> highest possible page available".

Well, in a way, they are for formatting really. Your layer doesn't need
any concept of a page per se since it really has nothing to do with
actually doing anything with the data.

> 3) There is nothing in any OOP literature I have read that says what I
> am doing is wrong, there it is not wrong.

I certainly wouldn't call it "wrong" that's for sure. You've simply
added a small bit of presentation logic to your class.

> Is this critocism justified or not?

I'd say not. If you took what you have and moved the
"formatting/presentation" bits into a separate class leaving just the
data manipulation bits in your class it might squash that criticism.

Personally I'd probably do it exactly the way you have since it's rare
that data manipulation and presentation are totally separate things
(IMO).

David Martin
DynaComp Solutions
http://DynaComp-Solutions.com

Andy Jeffries

unread,
Aug 7, 2003, 8:45:53 AM8/7/03
to
On Thu, 07 Aug 2003 12:16:55 +0000, Martin Wickman wrote:
>> 4) The language allows me to do it, therefore it cannot be wrong.
>
> Yup, otherwise you'd get a syntax error...

I disagree, something can be "wrong" as in an ugly way of doing something
but by syntactically correct.

However, I agree there is nothing wrong with what he is doing.

Cheers,


Andy

stephan beal

unread,
Aug 7, 2003, 10:15:19 AM8/7/03
to
Tony Marston wrote:
> $rows_per_page (to set the page size)
> $page_no (to request a particular page number)
> $lastpage (returns the highest possible page number)
>
> which he considers to related to formatting rather than the data
> itself, and as such is *bad* programming.

i wouldn't go so far as to say BAD, but i would consider it to be ill-suited
to the problem. i agree with him entirely that it's strictly formatting
info, and therefor has no place in a db abstraction layer. It does,
however, have a place in a DbTableRenderer, e.g., or a layer which builds
off of the db layer.

> 1) Those variables are not for *formatting*, they are for *data
> selection*.

No, they're not: consider that a PAGE is a layout convention, and layout is
formatting. Data selection has no unambigious concept of "page".

> 3) There is nothing in any OOP literature I have read that says what I
> am doing is wrong, there it is not wrong.

Yes, there is: most OO advocates will tell you to avoid ANY use of public
variables, for example.

> 4) The language allows me to do it, therefore it cannot be wrong.

The English language allows me to say many abusive things to you, but would
i be right in doing so? Languages are expressive tools, it's the
/expression/ of your solution which is not optimal: a) no public vars and
b) separate formatting from data.


> 5) It is simple and it works, therefore it cannot be all that bad.

If it serves the purpose, great, and that makes it good for it's purpose.
However, that almost inherently makes it less flexible for later adaption
into other contexts.


just my opinions, of course...

--
----- stephan beal
Registered Linux User #71917 http://counter.li.org
I speak for myself, not my employer. Contents may
be hot. Slippery when wet. Reading disclaimers makes
you go blind. Writing them is worse. You have been Warned.

matty

unread,
Aug 7, 2003, 3:36:13 PM8/7/03
to
Tony Marston wrote:

<snip>

> $rows_per_page (to set the page size)
> $page_no (to request a particular page number)
> $lastpage (returns the highest possible page number)
>
> which he considers to related to formatting rather than the data
> itself, and as such is *bad* programming.

I'd agree, and say that he's using the output buffer of the canal.

I've got something similar, although I have a subclass for paged output,
but much the same kind of thing.

Apart from nicer presentation, paging the results allows you to reduce
communication with the database server; if you insist on returning the
entire result set from the query, and *then* choosing a subset of it
from the PHP code, you introduce an unnecessary layer, which can be
done away with entirely by using "LIMIT x, y" in the query.

I think you've done it the right way (but then I would, 'cos I have too!)

> 5) It is simple and it works, therefore it cannot be all that bad.
>
> Do you people out there in PHP-land have any opinions on this matter?
> Is this critocism justified or not?

Definitely unjustified. Is he a first-year S/W Eng student by any chance???

matty

unread,
Aug 7, 2003, 3:37:38 PM8/7/03
to
The other point that occurs, is what is his stance on
using "LIMIT 0, 10", etc, in SQL?

Does he feel that it's bad, since the RDBMS is
taking part in presentation, which is wrong???

;-)

André Næss

unread,
Aug 7, 2003, 5:59:04 PM8/7/03
to
Tony Marston:

> On my website I have an article
> http://www.tonymarston.net/php-mysql/databaseobjects.html which
> describes an abstract class I have written to control all access to my
> databases. Someone who is supposed to be a respected member of the PHP
> community has informed me that my class breaks the rules of OO
> programming and is therefore unworthy of serious consideration. To be
> specific he complained that my class contains the following
> variables:-
>
> $rows_per_page (to set the page size)
> $page_no (to request a particular page number)
> $lastpage (returns the highest possible page number)
>
> which he considers to related to formatting rather than the data
> itself, and as such is *bad* programming.
>
> I personally think that he is talking out of the wrong end of his
> alimentary canal for the following reasons:-
>
> 1) Those variables are not for *formatting*, they are for *data
> selection*. When my presentation layer communicates with a database
> object it is basically saying "get me the data that satisfies this
> selection criteria" part of which is "based on a page size of
> $row_per_page get me the records for page $page_no, and tell me the
> highest possible page available".

The information is typical formatting information. I think it would be much
cleaner if you allowed for two more arguments to getData() that defined how
many rows to retrieve, and what offset to start at. The organization of
data into pages belongs in presentation code.

From a purist perspective, SQL operates on sets, and so operations like "get
me item 1 through 10" makes no sense since sets have no intrinsic ordering.
But the second one applies the SORT operator, the result is no longer a
set, but a list -- a structure with a defined order, and hence the
retrieval of rows 1 through 10 suddenly makes sense.

> 3) There is nothing in any OOP literature I have read that says what I
> am doing is wrong, there it is not wrong.

Right or wrong here is a matter of degree. If one agree that the variables
have to do with formatting, then what you have done is bad OO practice
according to a lot of people. The point is that good design typically
requires that classes have responsibilities, and it's not natural for a
database abstraction layer to be responsible for formatting.

> 4) The language allows me to do it, therefore it cannot be wrong.

Again, it depends on your usage of the word wrong. C allows me to write code
that generates random segmentation faults, and assembler allows me to write
self-modifying code.

> 5) It is simple and it works, therefore it cannot be all that bad.

I agree that it's simple and it does the job. But as far as I could
understand you wanted to submit your code to some sort of repository. When
code is to be used by many people it obviously has to be of much higher
quality than most of the code that's written every day, and -- more
importantly -- it must adhere to the principles accepted by most of the
developers who are supposed to use the code.

And in general I think your design is bad because you have to create a new
class for every table you create, and you have to recode both the table and
the class every time you change the table, which obviously doubles the
chances of bugs. I can't really see how this can save you very much work I
guess.

André Næss

Jochen Daum

unread,
Aug 7, 2003, 4:23:34 PM8/7/03
to
Hi Tony!

On 7 Aug 2003 04:45:59 -0700, to...@marston-home.demon.co.uk (Tony
Marston) wrote:

>On my website I have an article
>http://www.tonymarston.net/php-mysql/databaseobjects.html which
>describes an abstract class I have written to control all access to my
>databases. Someone who is supposed to be a respected member of the PHP
>community has informed me that my class breaks the rules of OO
>programming and is therefore unworthy of serious consideration. To be
>specific he complained that my class contains the following
>variables:-
>
>$rows_per_page (to set the page size)
>$page_no (to request a particular page number)
>$lastpage (returns the highest possible page number)
>
>which he considers to related to formatting rather than the data
>itself, and as such is *bad* programming.
>

The others wrote everything I could write.

My database class also supports a limit statement, I especially wrote
it, because its such a hassle to limit with MSSQL.

IMO, doesn't matter, if irt is parameter or class variable. I prefer
parameter, because I don't like:

$arith->x = 1;
$arith->y = 2;
$m = arith->multiply();

I rather like:

$m = arith->multiply(1,2);

HTH, Jochen


>I personally think that he is talking out of the wrong end of his
>alimentary canal for the following reasons:-
>
>1) Those variables are not for *formatting*, they are for *data
>selection*. When my presentation layer communicates with a database
>object it is basically saying "get me the data that satisfies this
>selection criteria" part of which is "based on a page size of
>$row_per_page get me the records for page $page_no, and tell me the
>highest possible page available".
>
>2) Despite me asking him what he considers to be the *right* way of
>doing things he has failed to respond, probably because he doesn't
>know the answer.
>
>3) There is nothing in any OOP literature I have read that says what I
>am doing is wrong, there it is not wrong.
>
>4) The language allows me to do it, therefore it cannot be wrong.
>
>5) It is simple and it works, therefore it cannot be all that bad.
>
>Do you people out there in PHP-land have any opinions on this matter?
>Is this critocism justified or not?
>
>Tony Marston
>http://www.tonymarston.net/

--
Jochen Daum - CANS Ltd.
PHP DB Edit Toolkit -- PHP scripts for building
database editing interfaces.
http://sourceforge.net/projects/phpdbedittk/

matty

unread,
Aug 7, 2003, 6:27:34 PM8/7/03
to
André Næss wrote:

<snip>

> The information is typical formatting information. I think it would be
> much cleaner if you allowed for two more arguments to getData() that
> defined how many rows to retrieve, and what offset to start at. The
> organization of data into pages belongs in presentation code.

The information is used to select a subset of the data, so how is this
formatting? Just because this kind of technique is commonly used in
presentation, doesn't mean that restricting the rows returning is a
formatting operation. If you were to take that viewpoint, then you
could argue that since the order records are displayed in a table is
presentational, then ordering the records returned is also a formatting
operation.

I do think that a GetPagedChunk($offset, $length) method could be a good
idea; however, the concepts of orthogonality and encapsulation would
indicate that having created a PagedResultSet($sourcequery, $pagelimit, $offset=0)
object (or similar), really, the object should handle issues such as which
records to return.

This *can* verge into formatting, but it's a trciky question: the presentational
requirements of displaying a table of data, along with "Showing records 5-19 of 235",
generation of next/previous links, etc, leads to a very heterogeneous set of data
to be returned by the object. One possible way to handle this is to have
GetPageNumber(), GetPageCount(), GetNextOffset(), etc, methods; another is to
return data as xml for transformation into the desired *format* for display, since
a generalized class cannot "know" the format required, etc.

>
> From a purist perspective, SQL operates on sets, and so operations like
> "get me item 1 through 10" makes no sense since sets have no intrinsic
> ordering. But the second one applies the SORT operator, the result is no
> longer a set, but a list -- a structure with a defined order, and hence
> the retrieval of rows 1 through 10 suddenly makes sense.

Arguing whether this is a part of a true relational query or not is fairly
academic as far as developing an application goes: very few large-scale applications
are built using databases in 5NF, since performance issues take a part. Sets have
no intrinsic ordering, but most people writing this type of class apply some
kind of ordering to the set returned, so that taking "records 16-20 of 33" has
some kind of meaningful semantic.

> Right or wrong here is a matter of degree. If one agree that the variables
> have to do with formatting, then what you have done is bad OO practice
> according to a lot of people. The point is that good design typically
> requires that classes have responsibilities, and it's not natural for a
> database abstraction layer to be responsible for formatting.

Good OO is about code reuse, orthogonality, and data encapsulation. Since the
data access class is there to handle the database queries, wouldn't it be
breaking the encapsulation to have a separate entity control which data is
actually displayed?

One of the funny things about this kind of application is that selecting
a subset of the data sits somewhere between database handling and presentation.
Reducing the number of records displayed reduces the overhead on 1) user
screens (and user brains); and on 2) the system serving the pages. I still
think there is a strong case that this kind of class doesn't have to violate
principles of OO; even if it did, the issues of performance dictate that it's
better to have the class function in this way, to increase code reliability and
reuse. People use OO to produce more reliable software, more rapidly: just
because a system is OO doesn't make it good in itself, it merely means it
has been written to conform to a specific paradigm.

> I agree that it's simple and it does the job. But as far as I could
> understand you wanted to submit your code to some sort of repository. When
> code is to be used by many people it obviously has to be of much higher
> quality than most of the code that's written every day, and -- more
> importantly -- it must adhere to the principles accepted by most of the
> developers who are supposed to use the code.
>
> And in general I think your design is bad because you have to create a new
> class for every table you create, and you have to recode both the table
> and the class every time you change the table, which obviously doubles the
> chances of bugs. I can't really see how this can save you very much work I
> guess.

Why do you have to recode the class? Admittedly, in the tutorial mentioned, the
number of rows per page is set in the constructor; there is no reason why the
variable cannot be changed. The same applies to the table name and database name.

As far as code quality is concerned, there are things missing (escaping the data
for one). But from a reusability point of view, mostly all that needs changing
is to pass a few parameters to the constructor, and add sorting to the queries
to get consistent results.

I think, though, that the page was meant more as a tutorial on writing classes
in PHP, and as such is better than many of those around online to date.

Zurab Davitiani

unread,
Aug 7, 2003, 6:33:15 PM8/7/03
to
stephan beal wrote on Thursday 07 August 2003 07:15:

> Tony Marston wrote:
>> 1) Those variables are not for *formatting*, they are for *data
>> selection*.
>
> No, they're not: consider that a PAGE is a layout convention, and layout
> is formatting. Data selection has no unambigious concept of "page".

Paging the data is being used by most databases that feature variable-length
records, such as Access, MSSQL, and others. While Tony's implementation
does not exactly serve the same purpose, it still goes to show that "page"
is not necessarily related to a presentation layer.

It seems to me that the issue here is with the naming of the properties with
"page" in them, not the merits of the properties, methods and
functionalities they provide. I believe it is perfectly acceptable for a
data layer to be able to divide data into "chunks" and only return
requested appropriate chunk(s) to the calling object/component/service/etc.

>> 3) There is nothing in any OOP literature I have read that says what I
>> am doing is wrong, there it is not wrong.
>
> Yes, there is: most OO advocates will tell you to avoid ANY use of public
> variables, for example.

Yes, I spotted this too and you are absolutely right.

--
Business Web Solutions
ActiveLink, LLC
www.active-link.com/intranet/

matty

unread,
Aug 7, 2003, 7:41:40 PM8/7/03
to
stephan beal wrote:


> Yes, there is: most OO advocates will tell you to avoid ANY use of public
> variables, for example.
>

Then you're screwed in PHP, since it doesn't support a top-level "application"
object; the closest you could get, is have an object that does everything from
its constuctor, and start it all off with

new MyApplication();

but that's probably at least a *little* counterintuitive...

Tony Marston

unread,
Aug 8, 2003, 3:22:24 AM8/8/03
to
André Næss <andrena.spa...@ifi.uio.no> wrote in message news:<bguasp$rbr$1...@maud.ifi.uio.no>...

Rather have have extra arguments in my 'getData' method I have
separate setters for $rows_per_page and $pageno, with a getter for
$lastpage. The reason for this is that a default value for
$rows_per_page can be defined in the class constructor.

> From a purist perspective, SQL operates on sets, and so operations like "get
> me item 1 through 10" makes no sense since sets have no intrinsic ordering.
> But the second one applies the SORT operator, the result is no longer a
> set, but a list -- a structure with a defined order, and hence the
> retrieval of rows 1 through 10 suddenly makes sense.

My point is that the presentation layer asks the database object to
retrieve some data, and it is the database object is responsible for
constructing the SQL statement. As the SQL statement contains the
'LIMIT x,y' clause it is necessary for the database object to have
these values available. There is simply no other way.

> > 3) There is nothing in any OOP literature I have read that says what I
> > am doing is wrong, there it is not wrong.
>
> Right or wrong here is a matter of degree. If one agree that the variables
> have to do with formatting, then what you have done is bad OO practice
> according to a lot of people. The point is that good design typically
> requires that classes have responsibilities, and it's not natural for a
> database abstraction layer to be responsible for formatting.

Those variables are not used for *formatting* the data, they are used
for *selecting* a subset of rows instead of the entire contents of the
table which would be grossly inefficient.



> > 4) The language allows me to do it, therefore it cannot be wrong.
>
> Again, it depends on your usage of the word wrong. C allows me to write code
> that generates random segmentation faults, and assembler allows me to write
> self-modifying code.

I am aware that certain languages have functions which are more
trouble than they are worth (I remember the ALTER verb in COBOL) but
that is irrelevant in this case. I do not see why it could possibly be
*wrong* to have a variable in my database object which allows that
database object to construct the LIMIT clause in an sql SELECT
statement.

> > 5) It is simple and it works, therefore it cannot be all that bad.
>
> I agree that it's simple and it does the job. But as far as I could
> understand you wanted to submit your code to some sort of repository. When
> code is to be used by many people it obviously has to be of much higher
> quality than most of the code that's written every day, and -- more
> importantly -- it must adhere to the principles accepted by most of the
> developers who are supposed to use the code.

I have been a software developer for over 25 years and I have seen
many different programmers with many different principles. Some try to
produce code which is efficient, effective and maintainable then write
a methodology to match, while others create a fancy methodology
without any regard for efficiency or maintainability. As far as I am
concerned the overriding principle is the KISS principle (Keep It
Simple, Stupid). Too many people keep inventing stupid rules which
just get in the way of efficient software development. Too many people
have different ideas about what is *good* and *not good* practice. As
far as I am concerned if it works, is simple and is maintainable then
it is *good*. Anything else is *not good*.

> And in general I think your design is bad because you have to create a new
> class for every table you create, and you have to recode both the table and
> the class every time you change the table, which obviously doubles the
> chances of bugs. I can't really see how this can save you very much work I
> guess.

> André Næss

You have missed the point about my abstract database class. Each
database table has its own class which is a subclass of the abstract
class, therefore it inherits all the properties and methods of the
abstract class. Each table class therefore need only contain extra
code which is specific to that class, such as a list of field names,
validation rules, relationships, etc. All the code for retrieving,
inserting, updating, deleting and validating data is inherited from
the abstract class and does not have to be rewritten or copied.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 8, 2003, 3:29:21 AM8/8/03
to
Dave Martin <DJMa...@DynaComp-Solutions.com> wrote in message news:<MPG.199c0e595...@news.east.earthlink.net>...

> In article <7588a50f.03080...@posting.google.com>,
> to...@marston-home.demon.co.uk says...
>
> > http://www.tonymarston.net/php-mysql/databaseobjects.html which
> > describes an abstract class I have written to control all access to my
> > databases.
>
> Nicely done Tony.

Thanks.

> > 1) Those variables are not for *formatting*, they are for *data
> > selection*. When my presentation layer communicates with a database
> > object it is basically saying "get me the data that satisfies this
> > selection criteria" part of which is "based on a page size of
> > $row_per_page get me the records for page $page_no, and tell me the
> > highest possible page available".
>
> Well, in a way, they are for formatting really. Your layer doesn't need
> any concept of a page per se since it really has nothing to do with
> actually doing anything with the data.

They are not *formatting* the data, they are used for *selecting* rows
from the database in the same way as 'where columnname=value' is used
for selection. The only *formatting* which is done is when the HTML
code is generated, which is done using an XML file and an XSL
transformation.

> > 3) There is nothing in any OOP literature I have read that says what I
> > am doing is wrong, there it is not wrong.
>
> I certainly wouldn't call it "wrong" that's for sure. You've simply
> added a small bit of presentation logic to your class.
>
> > Is this critocism justified or not?
>
> I'd say not. If you took what you have and moved the
> "formatting/presentation" bits into a separate class leaving just the
> data manipulation bits in your class it might squash that criticism.
>
> Personally I'd probably do it exactly the way you have since it's rare
> that data manipulation and presentation are totally separate things
> (IMO).

The database object needs to construct the sql SELECT statement, which
contains the LIMIT clause. It is therefore imperative that the
database object has the information available to construct the LIMIT
clause. There is simply no other way.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 8, 2003, 3:36:18 AM8/8/03
to
stephan beal <ste...@wanderinghorse.net> wrote in message news:<bgtmob$8lm$1...@ork.noris.net>...

> Tony Marston wrote:
> > $rows_per_page (to set the page size)
> > $page_no (to request a particular page number)
> > $lastpage (returns the highest possible page number)
> >
> > which he considers to related to formatting rather than the data
> > itself, and as such is *bad* programming.
>
> i wouldn't go so far as to say BAD, but i would consider it to be ill-suited
> to the problem. i agree with him entirely that it's strictly formatting
> info, and therefor has no place in a db abstraction layer. It does,
> however, have a place in a DbTableRenderer, e.g., or a layer which builds
> off of the db layer.
>
> > 1) Those variables are not for *formatting*, they are for *data
> > selection*.
>
> No, they're not: consider that a PAGE is a layout convention, and layout is
> formatting. Data selection has no unambigious concept of "page".

Those variables are for SELECTION as they are used to construct the
LIMIT clause on the sql SELECT statement. Even if the sql statement is
generated in a separate object these variables must be passed to that
object, therefore they must exist in my database class.

> > 3) There is nothing in any OOP literature I have read that says what I
> > am doing is wrong, there it is not wrong.
>
> Yes, there is: most OO advocates will tell you to avoid ANY use of public
> variables, for example.

I only use public variables because PHP 4 does not cater for private
variables. I am aware however that these variables should only be
accessed through separate setters and getters, which is what I use.

> > 4) The language allows me to do it, therefore it cannot be wrong.
>
> The English language allows me to say many abusive things to you, but would
> i be right in doing so? Languages are expressive tools, it's the
> /expression/ of your solution which is not optimal: a) no public vars and
> b) separate formatting from data.

People who say that my method is *wrong* have yet to supply me their
version of a method which is *right*.

> > 5) It is simple and it works, therefore it cannot be all that bad.
>
> If it serves the purpose, great, and that makes it good for it's purpose.
> However, that almost inherently makes it less flexible for later adaption
> into other contexts.
>
>
> just my opinions, of course...

How can my method be inflexible?

stephan beal

unread,
Aug 8, 2003, 4:31:11 AM8/8/03
to
Tony Marston wrote:

> stephan beal <ste...@wanderinghorse.net> wrote in message

>> Yes, there is: most OO advocates will tell you to avoid ANY use of public
>> variables, for example.
>
> I only use public variables because PHP 4 does not cater for private
> variables. I am aware however that these variables should only be
> accessed through separate setters and getters, which is what I use.

Then don't publish the vars in your API and add functions to get at them
instead. Yes, it's not the most efficient solution, but it's simple to
implement and makes long-term maintenance simpler.


>> > 5) It is simple and it works, therefore it cannot be all that bad.
>>
>> If it serves the purpose, great, and that makes it good for it's purpose.
>> However, that almost inherently makes it less flexible for later adaption
>> into other contexts.
>>
>>
>> just my opinions, of course...
>
> How can my method be inflexible?

Let's say it's 6 months from now and your needs for your site have out-grown
what the framework of capable of. The question comes up: rewrite the site
or expand the existing framework? The more that a framework (i.e., your
database layer) is tied to a specific task, the less flexible it becomes
and the more difficult it becomes to re-use that code in other contexts.

i'm not at all saying that your db layer IS inflexible (i have no idea - i
haven't analysed it), but i am of the opinion that SELECT data, for
example, is in essence a formatting option (the WHERE clause, on the other
hand, is specifically a logic operation), and that shoe-horning such things
as paging into the db layer isn't necessary. i would first write the db
layer and then make another layer which includes the selection/limitation
code. What if i wanted to use your db layer but didn't want the paging
code? Is the class designed in such a way that i am forced to use it?
Just things to consider.

Glen Vermeylen

unread,
Aug 8, 2003, 8:22:54 AM8/8/03
to
A part of your solution is Object Oriented but I have some considerations:
Tables are part of a database, your approach only leaves room to work
with one database. If you create a database class (as in: $db = new
dataBase('server', 'username', 'password') you could have your table
class make use of this dataBase class as in $table = new
table($db->getLink()).
Then you can distanciate yourself from the whereabouts of the tables and
only worry about their data.
Considering your getData: this requires you to have insight into the
inner mechanics of your class (you have to set your desired pagesize,
and you have to go through trouble if you don't want to get the standard
subsequent pages, set by pagesize).
I suggest you have a method $table->getData(selection_criteria), which
gives you every result there is. Then you could have a method
$table->getPage(selection_criteria, pagesize='defaultvalue',
pagenumber='1'). (the "=" will use a defaultvalue, if you don't pass
that parameter).
Now you can make a getNextPage(), getPrevPage(), ... which do what you
can guess... :).
I don't know anything about error-handling with php, but you might want
to consider tying mysql-specific errors to your mysql-classes.
$results = $table->getPage(...);
if ($table->hasError())
$table->printError();
That way, with inheritance (and overriding) your $db errors can be
delegated to $table...

I hope this has been of any help.

ps: This is not written out of arrogance and I don't think I know it
better than anyone else. I'm just a student, and also was pondering
about a nice oo-approach to php/mysql scripting.
This is just a mere braindump.

Glen

Glen Vermeylen

unread,
Aug 8, 2003, 8:29:43 AM8/8/03
to
Oops, spotted some errors in my text:

"new table($db->getLink())" would offcourse be "new table($db)". The
user only knows that a table is part of a database, he shouldn't know
about the link.

"That way, with inheritance (and overriding) ... " should be "with
delegation ... "

:-)

André Næss

unread,
Aug 8, 2003, 2:27:59 PM8/8/03
to
matty:

> André Næss wrote:
>
> <snip>
>
>> The information is typical formatting information. I think it would be
>> much cleaner if you allowed for two more arguments to getData() that
>> defined how many rows to retrieve, and what offset to start at. The
>> organization of data into pages belongs in presentation code.
>
> The information is used to select a subset of the data, so how is this
> formatting? Just because this kind of technique is commonly used in
> presentation, doesn't mean that restricting the rows returning is a
> formatting operation. If you were to take that viewpoint, then you
> could argue that since the order records are displayed in a table is
> presentational, then ordering the records returned is also a formatting
> operation.

Ok let me try to clarify this. To fetch rows 1 through 10 is ok. Using limit
is ok. It's ok to define what subset of a sorted result set you want,
because that's part of the selection. I agree.

Here's the relevant code:
var $rows_per_page; // used in pagination
var $pageno; // current page number
var $lastpage; // highest page number

So what Tony has done is put *pagination* information into the DB-class, and
that is what I react to. He could insert two variables, $offset and
$numRows, and that would be ok. But the pagination belongs in the
presentation layer. It's a tiny difference, and not very important IMO, but
I still think it's worth pointing out.

>> And in general I think your design is bad because you have to create a
>> new class for every table you create, and you have to recode both the
>> table and the class every time you change the table, which obviously
>> doubles the chances of bugs. I can't really see how this can save you
>> very much work I guess.
>
> Why do you have to recode the class? Admittedly, in the tutorial
> mentioned, the number of rows per page is set in the constructor; there is
> no reason why the
> variable cannot be changed. The same applies to the table name and
> database name.

You have to write a new class which inherits the abstract class and has
variables to represent the fields in the DB. Quote from Tony's page:

function Database_Table ()
{
$this->tablename = 'default';
$this->dbname = 'default';
$this->rows_per_page = 10;

$this->fieldlist = array('column1', 'column2', 'column3');
$this->fieldlist['column1'] = array('pkey' => 'y');
} // constructor

The variable $fieldlist is used to list all the columns within that table,
and to identify which is the primary key. How this is used will become
apparent

End quote.

So when you add a field to your DB, you also have to change the class, this
sort of dependency can quickly lead to maintenance problems, especially if
someone else is supposed to use the classes.

André Næss

André Næss

unread,
Aug 8, 2003, 2:34:55 PM8/8/03
to
Tony Marston:

>> The information is typical formatting information. I think it would be
>> much cleaner if you allowed for two more arguments to getData() that
>> defined how many rows to retrieve, and what offset to start at. The
>> organization of data into pages belongs in presentation code.
>
> Rather have have extra arguments in my 'getData' method I have
> separate setters for $rows_per_page and $pageno, with a getter for
> $lastpage. The reason for this is that a default value for
> $rows_per_page can be defined in the class constructor.

But if you say that these variables are in fact selection criteria, then
certainly you must agree that seeing as $where is a collection of selection
criteria, and it's being passed to getData(), it would be much more
consistent to pass them as parameters!



>> From a purist perspective, SQL operates on sets, and so operations like
>> "get me item 1 through 10" makes no sense since sets have no intrinsic
>> ordering. But the second one applies the SORT operator, the result is no
>> longer a set, but a list -- a structure with a defined order, and hence
>> the retrieval of rows 1 through 10 suddenly makes sense.
>
> My point is that the presentation layer asks the database object to
> retrieve some data, and it is the database object is responsible for
> constructing the SQL statement. As the SQL statement contains the
> 'LIMIT x,y' clause it is necessary for the database object to have
> these values available. There is simply no other way.

And we agree on that. See my reply to "matty".



>> > 5) It is simple and it works, therefore it cannot be all that bad.
>>
>> I agree that it's simple and it does the job. But as far as I could
>> understand you wanted to submit your code to some sort of repository.
>> When code is to be used by many people it obviously has to be of much
>> higher quality than most of the code that's written every day, and --
>> more importantly -- it must adhere to the principles accepted by most of
>> the developers who are supposed to use the code.
>
> I have been a software developer for over 25 years and I have seen
> many different programmers with many different principles. Some try to
> produce code which is efficient, effective and maintainable then write
> a methodology to match, while others create a fancy methodology
> without any regard for efficiency or maintainability. As far as I am
> concerned the overriding principle is the KISS principle (Keep It
> Simple, Stupid). Too many people keep inventing stupid rules which
> just get in the way of efficient software development. Too many people
> have different ideas about what is *good* and *not good* practice. As
> far as I am concerned if it works, is simple and is maintainable then
> it is *good*. Anything else is *not good*.

KISS is a very good idea indeed. My point was that if you want to partake in
a community you have to follow the rules of the community, if you disagree,
you have to lobby your disagreement to the other members.



>> And in general I think your design is bad because you have to create a
>> new class for every table you create, and you have to recode both the
>> table and the class every time you change the table, which obviously
>> doubles the chances of bugs. I can't really see how this can save you
>> very much work I guess.
>
>

> You have missed the point about my abstract database class. Each
> database table has its own class which is a subclass of the abstract
> class, therefore it inherits all the properties and methods of the
> abstract class. Each table class therefore need only contain extra
> code which is specific to that class, such as a list of field names,
> validation rules, relationships, etc.

Precisely. And it is this code which leads to a problematic dependency
between the DB and the class. I understand the point of reusing code to
generate SELECT/INSERT/UPDATE/DELETE statements, but you can do that
without having to create a class for every table you have.

André Næss

matty

unread,
Aug 8, 2003, 4:38:30 PM8/8/03
to
André Næss wrote:

> Here's the relevant code:
> var $rows_per_page; // used in pagination
> var $pageno; // current page number
> var $lastpage; // highest page number
>
> So what Tony has done is put *pagination* information into the DB-class,
> and that is what I react to. He could insert two variables, $offset and
> $numRows, and that would be ok. But the pagination belongs in the
> presentation layer. It's a tiny difference, and not very important IMO,
> but I still think it's worth pointing out.
>

Well, certainly the values shouldn't be set in the constructor like
this, I agree. I still think that there is a place for a database class
that can handle pagination without outside help, although this does raise
issues as far as the heterogenous nature of the data it would have to
return (links, data values, etc)

> You have to write a new class which inherits the abstract class and has
> variables to represent the fields in the DB. Quote from Tony's page:
>
> function Database_Table ()
> {
> $this->tablename = 'default';
> $this->dbname = 'default';
> $this->rows_per_page = 10;
>
> $this->fieldlist = array('column1', 'column2', 'column3');
> $this->fieldlist['column1'] = array('pkey' => 'y');
> } // constructor
>

OK, I missed this one as I only scanned the article. Of course, a really
good DB class would identify the primary key itself, as the RDBMS can
provide this kind of information...

> So when you add a field to your DB, you also have to change the class,
> this sort of dependency can quickly lead to maintenance problems,
> especially if someone else is supposed to use the classes.

I agree entirely with you on this point - since the whole point of OO
is reusing code, not just an academic exercise, a class which cannot
be reused isn't very helpful!

Tony Marston

unread,
Aug 11, 2003, 6:06:59 AM8/11/03
to
stephan beal <ste...@wanderinghorse.net> wrote in message news:<bgvmv1$14d$1...@ork.noris.net>...

My method is correct according to the principles of the 3 tier
architecture in which the presentation layer talks to the business
layer which talks to the data access layer. It is not allowed for the
presentation layer to talk directly to the data access layer - it must
always go through thye business layer. Therefore (and this is the crux
of my argument) whatever information the data access layer needs to
construct the sql SELECT statement must go through the business layer.
That is why my business layer object contains variables for paging as
how else could the data access layer have the information required to
construct the LIMIT clause?

I think your idea of having data selection/limitation code in a
separate layer is totally wrong (but that's just my personal opinion).

> What if i wanted to use your db layer but didn't want the paging
> code? Is the class designed in such a way that i am forced to use it?
> Just things to consider.

If you want paging turned off (which I do in one of my test scripts)
then simply set $rows_per_page to zero, then my code will not generate
any LIMIT clause on the SELECT statement.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 11, 2003, 6:28:11 AM8/11/03
to
André Næss <andrena.spa...@ifi.uio.no> wrote in message news:<bh0iss$ba8$1...@maud.ifi.uio.no>...
> matty:
>
> > André Næss wrote:

<snip>

> Ok let me try to clarify this. To fetch rows 1 through 10 is ok. Using limit


> is ok. It's ok to define what subset of a sorted result set you want,
> because that's part of the selection. I agree.
>
> Here's the relevant code:
> var $rows_per_page; // used in pagination
> var $pageno; // current page number
> var $lastpage; // highest page number
>
> So what Tony has done is put *pagination* information into the DB-class, and
> that is what I react to. He could insert two variables, $offset and
> $numRows, and that would be ok. But the pagination belongs in the
> presentation layer. It's a tiny difference, and not very important IMO, but
> I still think it's worth pointing out.

You method of pagination is more complicated than mine, therefore
violates the KISS principle. In my method all the presentation object
has to do before calling the getData() method is as follows:

$dbobject->setRowsPerPage()
$dbobject->setPageNo()

Both of these are optional because there is a default value for
$rows_per_page inside the class, and $pageno will default to whatever
was used previously for this object in the current session.

My presentation layer does not calculate the offset as that is done
inside the data access layer - all it does is specify a page number
(which comes from a hyperlink in my pagination area).

<snip>



> You have to write a new class which inherits the abstract class and has
> variables to represent the fields in the DB. Quote from Tony's page:
>
> function Database_Table ()
> {
> $this->tablename = 'default';
> $this->dbname = 'default';
> $this->rows_per_page = 10;
>
> $this->fieldlist = array('column1', 'column2', 'column3');
> $this->fieldlist['column1'] = array('pkey' => 'y');
> } // constructor
>
> The variable $fieldlist is used to list all the columns within that table,
> and to identify which is the primary key. How this is used will become
> apparent
>
> End quote.
>
> So when you add a field to your DB, you also have to change the class, this
> sort of dependency can quickly lead to maintenance problems, especially if
> someone else is supposed to use the classes.
>
> André Næss

Having a separate class for each individual database table is supposed
to be a GOOD idea in OOP as it encapsulates all the information
required to read/write/update/delete that particular database table.
This includes a list of all fields and their characteristics so that
basic validation can be done by the code which is inherited from the
abstract class instead of having to write a separate set of validation
code for each table.

If the physical database table is changed then the class which
contains information about that table is also changed. This is not a
maintenance problem, it is basic common sense. If a programmer changes
a database table without updating the code which accesses that table
then he is a ****KING PLONKER of the first order. In my method there
is one class per table, so the changes have to be made in only one
place. What could be easier than that?

Tony Marston
http://tonymarston.net/

Tony Marston

unread,
Aug 11, 2003, 6:37:39 AM8/11/03
to
Jochen Daum <joche...@cans.co.nz> wrote in message news:<c6d5jv4v8gm18j1kf...@4ax.com>...
> Hi Tony!

<snip>

> The others wrote everything I could write.
>
> My database class also supports a limit statement, I especially wrote
> it, because its such a hassle to limit with MSSQL.
>
> IMO, doesn't matter, if irt is parameter or class variable. I prefer
> parameter, because I don't like:
>
> $arith->x = 1;
> $arith->y = 2;
> $m = arith->multiply();
>
> I rather like:
>
> $m = arith->multiply(1,2);
>
> HTH, Jochen
>

The reason that I use separate variables instead of parameters on the
getData() method is that the number of possible parameters is quite
large and most of them are optional. So instead of having a long list
of parameters on the getData() method I find it easier to use a
separate set...() method whenever I DO have a value that I want to be
used. That is my personal preference. If I have a method which has a
small number of parameters then I would stick to supplying them on the
method call as you suggest.

The difference lies in the number of parameters and how many of them
are optional.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 11, 2003, 6:58:26 AM8/11/03
to
Glen Vermeylen <gverm...@pandora.be> wrote in message news:<3F339559...@pandora.be>...

> A part of your solution is Object Oriented but I have some considerations:
> Tables are part of a database, your approach only leaves room to work
> with one database.

WRONG! My current development uses 3 different databases within the
same application. Each class is named after the table, but the
database name is held within the class and is transparent to the
presentation layer.

> If you create a database class (as in: $db = new
> dataBase('server', 'username', 'password') you could have your table
> class make use of this dataBase class as in $table = new
> table($db->getLink()).
> Then you can distanciate yourself from the whereabouts of the tables and
> only worry about their data.
> Considering your getData: this requires you to have insight into the
> inner mechanics of your class (you have to set your desired pagesize,
> and you have to go through trouble if you don't want to get the standard
> subsequent pages, set by pagesize).

There is a default page size defined within each class, but it can be
changed at any time using the $dbobject->setRowsPerPage() method. A
zero value will turn off paging altogether.

> I suggest you have a method $table->getData(selection_criteria), which
> gives you every result there is. Then you could have a method
> $table->getPage(selection_criteria, pagesize='defaultvalue',
> pagenumber='1'). (the "=" will use a defaultvalue, if you don't pass
> that parameter).
> Now you can make a getNextPage(), getPrevPage(), ... which do what you
> can guess... :).

I don't want a separate method for firstpage(), previouspage(),
nextpage(), lastpage() when I can use a setPageNo() method followed by
my getData() method.

> I don't know anything about error-handling with php, but you might want
> to consider tying mysql-specific errors to your mysql-classes.
> $results = $table->getPage(...);
> if ($table->hasError())
> $table->printError();
> That way, with inheritance (and overriding) your $db errors can be
> delegated to $table...

Take a look at http://www.tonymarston.net/php-mysql/errorhandler.html

> I hope this has been of any help.
>
> ps: This is not written out of arrogance and I don't think I know it
> better than anyone else. I'm just a student, and also was pondering
> about a nice oo-approach to php/mysql scripting.
> This is just a mere braindump.
>
> Glen

You have to learn somehow, but something you have to watch out for is
that different people have different ideas about what is *good* or
*not good* programming. My advice is as follows:

- Try to follow the KISS principle and you won't go far wrong.

- When developing software there should only be 3 limiting factors:
1) The limits imposed by the user requirements.
2) The limits imposed by the chosen development language.
3) The limits of you own abilities.

Other limitations, such as people telling you which methodology is
*right* or even which interpretation of the methodology is *right*,
are entirely artificial and therefore can be ignored.

Tony Marston
http://www.tonymarston.net/

matty

unread,
Aug 11, 2003, 8:19:40 AM8/11/03
to
Tony Marston wrote:

<snip>

I have to disagree with you here! Having a separate class *instance* is
good OO, having a separate *class* is bad OO, since you lose all the
potential benefits of low maintenance, etc.

>
> If the physical database table is changed then the class which
> contains information about that table is also changed. This is not a
> maintenance problem, it is basic common sense. If a programmer changes
> a database table without updating the code which accesses that table
> then he is a ****KING PLONKER of the first order. In my method there
> is one class per table, so the changes have to be made in only one
> place. What could be easier than that?
>

How about something like this:

(obviously not a specific implementation, more a hypothetical description
of an interface)

$tablea = new DBTable($database, $user, $password, $table);
foreach(array('widgetid', 'manufr', 'cost', 'colour', 'weight') as $item)
{
$tablea->AddField($item);
}
$tablea->AddConstraint('cost > 20.00');
$tablea->AddConstraint('colour = \'blue\'');
if (!array_key_exists('offset', $_GET) or !preg_match('/^[0-9]+/', $_GET['offset']))
{
$dboffset = 0;
}
$resultarray = $tablea->GetPageList($offset, $config['database']['pagelength']);

Then you can change database, change fields, paging length, WHERE constraints, etc
without having to change the *class*, merely the class instance. You only have to change
DBTable class code if you're changing its functionality.

Otherwise, in a system with 12 database tables, having a different class for each
table? That's not good.

Matt

R. Rajesh Jeba Anbiah

unread,
Aug 11, 2003, 10:09:03 AM8/11/03
to
to...@marston-home.demon.co.uk (Tony Marston) wrote in message news:<7588a50f.03080...@posting.google.com>...

Kudos! Nice work... My points regarding the OOP style:

1. I could see the way you pass values to the methods contradicts the
OOP style. For example:

global $dbconnect, $query; <=======//
$dbconnect = db_connect($this->dbname) or trigger_error("SQL",
E_USER_ERROR);

at the "updateRecord ($fieldarray)" method.

You could have used setDBLink($db_link) to the class....

2.

function Database_Table ()
{
$this->tablename = 'default';
$this->dbname = 'default';
$this->rows_per_page = 10;

$this->fieldlist = array('column1', 'column2', 'column3');
$this->fieldlist['column1'] = array('pkey' => 'y');
} // constructor

If you this style, there won't be any reusability. In the
languages that support associative arrays, you may use like...
function Database_Table ()
{
$this->table_settings = array(); //hash array
} // constructor

Then...
function setTableSettings($key, $value)
{
$this->table_settings[$key] = $value;
}

function getTableSettings($key)
{
return( $this->table_settings[$key] );
}


This is my point. I may be wrong though...

Anyway... keep writing... nice article...

---
"If there is a God, he must be a sadist!"
Email: rrjanbiah-at-Y!com

André Næss

unread,
Aug 11, 2003, 4:42:15 PM8/11/03
to
Tony Marston:

> André Næss <andrena.spa...@ifi.uio.no> wrote in message
> news:<bh0iss$ba8$1...@maud.ifi.uio.no>...
>> matty:
>>
>> > André Næss wrote:
>
> <snip>
>
>> Ok let me try to clarify this. To fetch rows 1 through 10 is ok. Using
>> limit is ok. It's ok to define what subset of a sorted result set you
>> want, because that's part of the selection. I agree.
>>
>> Here's the relevant code:
>> var $rows_per_page; // used in pagination
>> var $pageno; // current page number
>> var $lastpage; // highest page number
>>
>> So what Tony has done is put *pagination* information into the DB-class,
>> and that is what I react to. He could insert two variables, $offset and
>> $numRows, and that would be ok. But the pagination belongs in the
>> presentation layer. It's a tiny difference, and not very important IMO,
>> but I still think it's worth pointing out.
>
> You method of pagination is more complicated than mine, therefore
> violates the KISS principle. In my method all the presentation object
> has to do before calling the getData() method is as follows:

How is it more complicated? All I suggest is that you let the presentation
layer handle a presentation issue. It's really simple to supply the
presentation layer with default values for the pagination, and if you want
to change those values you have to change them *somewhere*. It just makes
more sense to change them in the presentation layer and let the
presentation layer handle the translation from offset/page number to the
limit clause. Transparently, of course.

Now, if I was to code this I'd probably write a sort of
PagedPresentation thingy, which is meant for this sort of
situation. PagedPresentation should just supply a framework for
creating paged presentations, and it has to be coupled with a data
source. The data source supplies the PagedPresentation with data, and
the PagedPresentation transforms these data as defined by the
developer using some sort of template (a simple HTML/PHP mix is
sufficient).

But there obviously has to be a connection between the data source and
the presentation, because the presentation outputs stuff which in the
end has to result in $_GET variables which define what page to
display. And this data then has to be used to figure out what rows to
fetch.

So, we have to figure out how to implement this as clean as
possible. Let us start by considering the purist solution, which is to
fetch *all* the rows and supply them to the presentation layer, which
outputs the rows in question. How do we achieve this? Well, presumably
we have a structure where a presentation module must request data from
it's data source, so in the presentation module we have something like
this:

$collection = $source->getData();

The source defines *what* the data are, of course. In most cases a
data source is just an abstraction of a particular SQL query.
getData() returns an collection, because after all, we are requesting
a (possibly empty) collection of data.

So now the presentation layer is about to begin it's work, what we in
a PagedPresentation would expect is something like this:

$offset = $_GET['pageNum'] * $itemsPerPage;
$data = range($collection, $offset, $itemsPerPage)
applyTemplate($data);

So does this interface make sense? It does IMO, and it can be
implemented in a fashion that makes it as efficient as a solution
which supplies the offset and the number of items per page at an
earlier stage. Why? Because we don't have to actually perform the
query until the data are accessed, and they aren't really accessed
until applyTemplate() is called! In this case range() is a selection
utility which defines a certain subrange of the collection, but it doesn't
really have to do it, nor does $source need be an actual query result, they
are just a facade designed to make the interface coherent and highly
reusable, the implementation can be made as efficient as possible using any
trick in the book.

So let me stress that this was the *implementation* of PagedPresentation, to
use PagedPresentation we would expect an interface like this:

$source = new DataSource("SELECT ALL RED CARS FROM 1998");
$presentation = new PagedPresentation($source, $templateFile, $itemsPrPage);
$presentation->display();

All highly simplified, of course.

> $dbobject->setRowsPerPage()
> $dbobject->setPageNo()
>
> Both of these are optional because there is a default value for
> $rows_per_page inside the class, and $pageno will default to whatever
> was used previously for this object in the current session.

And the same can be done if you put this stuff in the presentation layer. I
don't see the problem.



> My presentation layer does not calculate the offset as that is done
> inside the data access layer - all it does is specify a page number
> (which comes from a hyperlink in my pagination area).

I you think that such a basic calculation violates KISS, then you're taking
it too far IMO. And besides, it's more important to apply KISS interfaces.
In this case you have a less than perfectly clean, and IMO less intuitive
interface.

>> You have to write a new class which inherits the abstract class and has
>> variables to represent the fields in the DB. Quote from Tony's page:
>>
>> function Database_Table ()
>> {
>> $this->tablename = 'default';
>> $this->dbname = 'default';
>> $this->rows_per_page = 10;
>>
>> $this->fieldlist = array('column1', 'column2', 'column3');
>> $this->fieldlist['column1'] = array('pkey' => 'y');
>> } // constructor
>>
>> The variable $fieldlist is used to list all the columns within that
>> table, and to identify which is the primary key. How this is used will
>> become apparent
>>
>> End quote.
>>
>> So when you add a field to your DB, you also have to change the class,
>> this sort of dependency can quickly lead to maintenance problems,
>> especially if someone else is supposed to use the classes.
>>
>

> Having a separate class for each individual database table is supposed
> to be a GOOD idea in OOP as it encapsulates all the information
> required to read/write/update/delete that particular database table.
> This includes a list of all fields and their characteristics so that
> basic validation can be done by the code which is inherited from the
> abstract class instead of having to write a separate set of validation
> code for each table.

Well, there's a much more interesting principle that applies here, and that
is the principle of orthogonality. You want to achieve two goals, that of
being able to simplify and reuse INSERT/UPDATE/DELETE/SELECT code, and that
of being able to validate data.

There is a very common error which people do the first time they do OO, and
that is to overuse inheritance. It's not that strange really as there's
always a lot og fighting over inheritance. But object composition is a
second technique that frequently applies, you can read more about this in
[1] (p. 18-20). In this case you can write two classes, and through object
composition solve the same problem. You won't need to write new classes to
handle new tables, which certainly is a lot simpler and cleaner.

If you think about it, it really makes sense. *Validating* data is a
completely different thing from ferrying data back and forth between a
DBMS, so why should the two be merged into one schizophrenic class?

Data-directed programming is the heart of OO, and this is brilliantly
covered in [2]. If you really want to understand OO I suggest giving it a
read. It teaches the basic principles that underlies OO, and it does so
without drowning the dicussion in empty buzzwords. A true gem.



> If the physical database table is changed then the class which
> contains information about that table is also changed. This is not a
> maintenance problem, it is basic common sense. If a programmer changes
> a database table without updating the code which accesses that table
> then he is a ****KING PLONKER of the first order.

Certainly there are plenty of cases when you need to rewrite parts of the
system due to changes in the database, but the it's still important to
*minimize* the number of such changes that need to be made.

> In my method there
> is one class per table, so the changes have to be made in only one
> place. What could be easier than that?

One where there is just two classes regardless of the number of tables, so
you didn't have to make any changes :)

One of your early complaints was that people just said you were wrong
without pointing out a better way. I think there's been plenty of ideas on
how to improve the design by now :)

André Næss

References:
[1] Gamma et.al., Design Patterns
http://www.amazon.com/exec/obidos/tg/detail/-/0201633612/qid=1060622571/sr=8-1/ref=sr_8_1/002-8378363-3212024?v=glance&s=books&n=507846

[2] Abelson and Sussman, Structure and Interpretation of Computer Programs,
Chapter 2 "Building Abstraction with Data"
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-13.html#%_chap_2

André Næss

unread,
Aug 11, 2003, 4:47:09 PM8/11/03
to
Tony Marston:

> The reason that I use separate variables instead of parameters on the
> getData() method is that the number of possible parameters is quite
> large and most of them are optional. So instead of having a long list
> of parameters on the getData() method I find it easier to use a
> separate set...() method whenever I DO have a value that I want to be
> used. That is my personal preference. If I have a method which has a
> small number of parameters then I would stick to supplying them on the
> method call as you suggest.
>
> The difference lies in the number of parameters and how many of them
> are optional.

Keyword arguments are very practical in this type of problem, but they are
unfortunately not supported by PHP. A common workaround is to use assoc
arrays to pass the parameters, something that had felt a lot cleaner had
PHP supported a more practical array notation than
array('a'=>1, 'b'=>2, 'c'=>3).

My favorite:
['a': 1, 'b': 2, 'c': 3]

André Næss

Jochen Daum

unread,
Aug 11, 2003, 5:55:45 PM8/11/03
to
Hi Tony!
On 11 Aug 2003 03:28:11 -0700, to...@marston-home.demon.co.uk (Tony
Marston) wrote:

snip


>
>Having a separate class for each individual database table is supposed
>to be a GOOD idea in OOP as it encapsulates all the information
>required to read/write/update/delete that particular database table.
>This includes a list of all fields and their characteristics so that
>basic validation can be done by the code which is inherited from the
>abstract class instead of having to write a separate set of validation
>code for each table.

I disagree here. This means you write the same code for each table -
select, insert, update, delete again and again. But basically its
always the same.

>
>If the physical database table is changed then the class which
>contains information about that table is also changed. This is not a
>maintenance problem,

It is, if there is a standard way to handle a varchar, or a datetime.

> it is basic common sense. If a programmer changes
>a database table without updating the code which accesses that table
>then he is a ****KING PLONKER of the first order.

Understood.

> In my method there
>is one class per table, so the changes have to be made in only one
>place. What could be easier than that?

One class for all. Changes are made in a data dictionary. That the
approach I take daily. You can see it in the project below.

Jochen

Tony Marston

unread,
Aug 12, 2003, 3:01:06 AM8/12/03
to
Jochen Daum <joche...@cans.co.nz> wrote in message news:<h14gjv8lr2r35qdt1...@4ax.com>...

> Hi Tony!
> On 11 Aug 2003 03:28:11 -0700, to...@marston-home.demon.co.uk (Tony
> Marston) wrote:
>
> snip
> >
> >Having a separate class for each individual database table is supposed
> >to be a GOOD idea in OOP as it encapsulates all the information
> >required to read/write/update/delete that particular database table.
> >This includes a list of all fields and their characteristics so that
> >basic validation can be done by the code which is inherited from the
> >abstract class instead of having to write a separate set of validation
> >code for each table.
>
> I disagree here. This means you write the same code for each table -
> select, insert, update, delete again and again. But basically its
> always the same.

No I do not write the same code again and again. The code which
handles select/insert/update/delete is inherited from the parent class
so it is inherited by every subclass.


> >If the physical database table is changed then the class which
> >contains information about that table is also changed. This is not a
> >maintenance problem,
>
> It is, if there is a standard way to handle a varchar, or a datetime.

By 'standard' processing I mean the following:-
- for char/varchar, is it required or optional? does it exceed the max
length?
- for datetime, is the date portion a valid date?, is the time portion
a valid time?
- for numbers, is the input valid numeric? is it signed or unsigned?
does it have too many significant digits? does it have too many
decimal digits?
- for key fields, is the key already in use?

Non-standard validation, such as 'is date A greater than date B?' is
handled by custom code within the class for that table.

> > it is basic common sense. If a programmer changes
> >a database table without updating the code which accesses that table
> >then he is a ****KING PLONKER of the first order.
>
> Understood.
>
> > In my method there
> >is one class per table, so the changes have to be made in only one
> >place. What could be easier than that?
>
> One class for all. Changes are made in a data dictionary. That the
> approach I take daily. You can see it in the project below.
>
> Jochen

My data dictionary is held within each table class, not in a separate
database. I do not want the overhead of accessing a separate database
to get at my validation rules.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 12, 2003, 3:13:18 AM8/12/03
to
matty <matt...@askmenoquestions.co.uk> wrote in message news:<%1LZa.1232$z7.3...@wards.force9.net>...
> Tony Marston wrote:
>
> <snip>

>
> > Having a separate class for each individual database table is supposed
> > to be a GOOD idea in OOP as it encapsulates all the information
> > required to read/write/update/delete that particular database table.
> > This includes a list of all fields and their characteristics so that
> > basic validation can be done by the code which is inherited from the
> > abstract class instead of having to write a separate set of validation
> > code for each table.
>
> I have to disagree with you here! Having a separate class *instance* is
> good OO, having a separate *class* is bad OO, since you lose all the
> potential benefits of low maintenance, etc.

I disagree most strongly. I have a separate class for each database
table as that contains the validation rules and special processing
considerations for that table. This is called 'encapsulation' which is
*good* OO programming. If there is only one class for ALL database
tables then where do I put the business rules for each individual
table? Where is the encapsulation in that idea?


> How about something like this:
>
> (obviously not a specific implementation, more a hypothetical description
> of an interface)
>
> $tablea = new DBTable($database, $user, $password, $table);
> foreach(array('widgetid', 'manufr', 'cost', 'colour', 'weight') as $item)
> {
> $tablea->AddField($item);
> }
> $tablea->AddConstraint('cost > 20.00');
> $tablea->AddConstraint('colour = \'blue\'');
> if (!array_key_exists('offset', $_GET) or !preg_match('/^[0-9]+/', $_GET['offset']))
> {
> $dboffset = 0;
> }
> $resultarray = $tablea->GetPageList($offset, $config['database']['pagelength']);
>
> Then you can change database, change fields, paging length, WHERE constraints, etc
> without having to change the *class*, merely the class instance. You only have to change
> DBTable class code if you're changing its functionality.
>
> Otherwise, in a system with 12 database tables, having a different class for each
> table? That's not good.
>
> Matt

Your idea requires too much effort. You have a generic table class
which contains no business rules, but you have a separate object which
creates an instance of this generic class then tells it what the
business rules are. In my method I do not build a class that tells the
generic class what the business rules are, I have a subclass which
contains those rules and which inherits all the generic code from the
base class.

We both seem to have a separate class for each table, but implemented
differently. I maintain that my method is easier.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 12, 2003, 3:30:56 AM8/12/03
to
André Næss <andrena.spa...@ifi.uio.no> wrote in message news:<bh0j9s$bar$1...@maud.ifi.uio.no>...

> Tony Marston:
>
> >> The information is typical formatting information. I think it would be
> >> much cleaner if you allowed for two more arguments to getData() that
> >> defined how many rows to retrieve, and what offset to start at. The
> >> organization of data into pages belongs in presentation code.
> >
> > Rather have have extra arguments in my 'getData' method I have
> > separate setters for $rows_per_page and $pageno, with a getter for
> > $lastpage. The reason for this is that a default value for
> > $rows_per_page can be defined in the class constructor.
>
> But if you say that these variables are in fact selection criteria, then
> certainly you must agree that seeing as $where is a collection of selection
> criteria, and it's being passed to getData(), it would be much more
> consistent to pass them as parameters!

The number of possible parameters on the getData() method is quite
large, and as most of them are optional I find it easier to use a
set..() method for each of these variables only when a value is
available. As I save each object in the session array it also means
that any value set in one operation is maintained throughout the
session until it is changed or reset.

Also, the number of values I want returned may be more than, and as
PHP only allows one value to be returned with each function call I
save this as a separate object variable and use a get..() method it is
needed.

> <snip>


> KISS is a very good idea indeed. My point was that if you want to partake in
> a community you have to follow the rules of the community, if you disagree,
> you have to lobby your disagreement to the other members.

What is obvious from the various postings in this thread is that
different people have totally different ideas about what is *good/not
good* OO programming. Some people prefer simple solutions while others
seem to go out of their way to invent the most convoluted solutions
just to satisfy their personal interpretations of the *rules* of OOP.
I follow the KISS principle.

> >> And in general I think your design is bad because you have to create a
> >> new class for every table you create, and you have to recode both the
> >> table and the class every time you change the table, which obviously
> >> doubles the chances of bugs. I can't really see how this can save you
> >> very much work I guess.
> >
> >
> > You have missed the point about my abstract database class. Each
> > database table has its own class which is a subclass of the abstract
> > class, therefore it inherits all the properties and methods of the
> > abstract class. Each table class therefore need only contain extra
> > code which is specific to that class, such as a list of field names,
> > validation rules, relationships, etc.
>
> Precisely. And it is this code which leads to a problematic dependency
> between the DB and the class. I understand the point of reusing code to
> generate SELECT/INSERT/UPDATE/DELETE statements, but you can do that
> without having to create a class for every table you have.
>
> André Næss

Then where do I maintain the business rules for each individual
database table? In a separate class? That is what I have, but each
table class is a subclass of the generic database class, not a
separate class in its own right.

Tony Marston
http://tonymarston.net/

Tony Marston

unread,
Aug 12, 2003, 3:34:09 AM8/12/03
to
André Næss <andrena.spa...@ifi.uio.no> wrote in message news:<bh8o4t$38m$2...@maud.ifi.uio.no>...

I prefer to use the features that the language does allow and not
waste my time in dreaming up features that it does not.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 12, 2003, 3:42:54 AM8/12/03
to
ng4rrj...@rediffmail.com (R. Rajesh Jeba Anbiah) wrote in message news:<abc4d8b8.03081...@posting.google.com>...

> to...@marston-home.demon.co.uk (Tony Marston) wrote in message news:<7588a50f.03080...@posting.google.com>...
> > On my website I have an article
> > http://www.tonymarston.net/php-mysql/databaseobjects.html
>
> Kudos! Nice work... My points regarding the OOP style:
>
> 1. I could see the way you pass values to the methods contradicts the
> OOP style. For example:

Contradicts what style? Where is this *style* documented?

> global $dbconnect, $query; <=======//
> $dbconnect = db_connect($this->dbname) or trigger_error("SQL",
> E_USER_ERROR);
>
> at the "updateRecord ($fieldarray)" method.
>
> You could have used setDBLink($db_link) to the class....

I could have done it in many different ways, but I am happy with the
method I have chosen. I see no reason to switch to another method
unless someone can point out some positive advantages.

> 2.
> function Database_Table ()
> {
> $this->tablename = 'default';
> $this->dbname = 'default';
> $this->rows_per_page = 10;
>
> $this->fieldlist = array('column1', 'column2', 'column3');
> $this->fieldlist['column1'] = array('pkey' => 'y');
> } // constructor
>
> If you this style, there won't be any reusability.

Then you do not understand OO programming. All the business rules for
a database table are maintained in a single class, so when any
presentation object wants to communicate with that table it uses that
table's class. Thus I can have many presentation objects all reusing
the same table class. That is where *reusability* comes from. This is
the basis of the 3 tier architecture which I used in a previous
language.

> <snip>

> This is my point. I may be wrong though...

You may well be!

Tony Marston
http://www.tonymarston.net/

R. Rajesh Jeba Anbiah

unread,
Aug 12, 2003, 10:01:18 AM8/12/03
to
to...@marston-home.demon.co.uk (Tony Marston) wrote in message news:<7588a50f.03081...@posting.google.com>...

> ng4rrj...@rediffmail.com (R. Rajesh Jeba Anbiah) wrote in message news:<abc4d8b8.03081...@posting.google.com>...
> > to...@marston-home.demon.co.uk (Tony Marston) wrote in message news:<7588a50f.03080...@posting.google.com>...
> > > On my website I have an article
> > > http://www.tonymarston.net/php-mysql/databaseobjects.html

> Contradicts what style? Where is this *style* documented?

> > global $dbconnect, $query; <=======//

This is what I meant---passing variables to the methods. This
style necessitates that you must have the variable "$dbconnect"
outside of the class. In otherwords, you should use/define the
variable "$dbconnect" whenever you use the class. IMO, this is not a
good practice/style. For example, I want to use your class and if
there is a mechanism to pass my "$DB___Connection__Link" variable to
your class, I can happily use the class without any modification. So,
my point is: this is not a good style to pass the variable to the
methods.


---> Contradicts what style? Where is this *style* documented?

All the time, we cannot refer the ___law books___... It comes from
the practice and excercises.


> > 2.
> > function Database_Table ()
> > {
> > $this->tablename = 'default';
> > $this->dbname = 'default';
> > $this->rows_per_page = 10;
> >
> > $this->fieldlist = array('column1', 'column2', 'column3');
> > $this->fieldlist['column1'] = array('pkey' => 'y');
> > } // constructor
> >
> > If you this style, there won't be any reusability.
>
> Then you do not understand OO programming.

Yes.

>All the business rules for
> a database table are maintained in a single class, so when any
> presentation object wants to communicate with that table it uses that
> table's class. Thus I can have many presentation objects all reusing
> the same table class. That is where *reusability* comes from. This is
> the basis of the 3 tier architecture which I used in a previous
> language.

I was refering *reusabiliy* on different projects (Not on a
single project in which your database is "foo" and table name is
"foo").

Also, if the class you mentioned is for single purpose, it's ok.
But, you've written a *tutorial*. Everybody who reads the *tutorial*
will be tempted to follow the style. If they follow the style, they
may suffer when it comes to reusability rules on more than 1 project.

> > This is my point. I may be wrong though...
>
> You may well be!

Yes... I'm wrong. But, IMO you're also not correct..

---
"Something is less than nothing"
Email: rrjanbiah-at-Y!com

Michiel

unread,
Aug 12, 2003, 10:35:47 AM8/12/03
to
Andy Jeffries wrote:

> On Thu, 07 Aug 2003 12:16:55 +0000, Martin Wickman wrote:
>
>>>4) The language allows me to do it, therefore it cannot be wrong.
>>
>>Yup, otherwise you'd get a syntax error...
>
>
> I disagree, something can be "wrong" as in an ugly way of doing something
> but by syntactically correct.
>
> However, I agree there is nothing wrong with what he is doing.
>

If we're talking about doing things wrong from an OOP point of view,
there's a shitload of things you can do wrong. This doesn't mean the
same thing is wrong from a PHP point of view, since PHP is not truly OO.

Michiel

unread,
Aug 12, 2003, 10:40:44 AM8/12/03
to
matty wrote:
> Tony Marston wrote:
>
> <snip>

>
>>$rows_per_page (to set the page size)
>>$page_no (to request a particular page number)
>>$lastpage (returns the highest possible page number)
>>
>>which he considers to related to formatting rather than the data
>>itself, and as such is *bad* programming.
>
>
> I'd agree, and say that he's using the output buffer of the canal.
>
> I've got something similar, although I have a subclass for paged output,
> but much the same kind of thing.
>
> Apart from nicer presentation, paging the results allows you to reduce
> communication with the database server; if you insist on returning the
> entire result set from the query, and *then* choosing a subset of it
> from the PHP code, you introduce an unnecessary layer, which can be
> done away with entirely by using "LIMIT x, y" in the query.

AND make it mysql dependent. The LIMIT clause is not widely supported.
Besides, mysql will most probably allocate the whole result set and
return only part of it, so it doesn't matter all that much.

>
> I think you've done it the right way (but then I would, 'cos I have too!)


>
>
>>5) It is simple and it works, therefore it cannot be all that bad.
>>

>>Do you people out there in PHP-land have any opinions on this matter?


>>Is this critocism justified or not?
>
>

> Definitely unjustified. Is he a first-year S/W Eng student by any chance???


Michiel

unread,
Aug 12, 2003, 10:48:32 AM8/12/03
to
Tony Marston wrote:
> On my website I have an article
> http://www.tonymarston.net/php-mysql/databaseobjects.html which
> describes an abstract class I have written to control all access to my
> databases. Someone who is supposed to be a respected member of the PHP
> community has informed me that my class breaks the rules of OO
> programming and is therefore unworthy of serious consideration. To be
> specific he complained that my class contains the following
> variables:-

>
> $rows_per_page (to set the page size)
> $page_no (to request a particular page number)
> $lastpage (returns the highest possible page number)
>
> which he considers to related to formatting rather than the data
> itself, and as such is *bad* programming.
>
> I personally think that he is talking out of the wrong end of his
> alimentary canal for the following reasons:-

>
> 1) Those variables are not for *formatting*, they are for *data
> selection*. When my presentation layer communicates with a database
> object it is basically saying "get me the data that satisfies this
> selection criteria" part of which is "based on a page size of
> $row_per_page get me the records for page $page_no, and tell me the
> highest possible page available".
>
> 2) Despite me asking him what he considers to be the *right* way of
> doing things he has failed to respond, probably because he doesn't
> know the answer.

>
> 3) There is nothing in any OOP literature I have read that says what I
> am doing is wrong, there it is not wrong.
>
> 4) The language allows me to do it, therefore it cannot be wrong.
>
> 5) It is simple and it works, therefore it cannot be all that bad.
>
> Do you people out there in PHP-land have any opinions on this matter?
> Is this critocism justified or not?
>
> Tony Marston
> http://www.tonymarston.net/

You've done a good job. Certainly. But.... if you learn some more about
OOP you could use it much more effective. And to be honest... a database
access layer is not the most difficult thing to write. You can afford to
make some design errors and still have a useful class. If you start
writing more complex software (probably soon) you would get into trouble
if you keep coding this style.

My advice:
- Learn some more about 'design patterns'. They can help you.
- Learn UML (unified modelling language), it helps you to first
conceptualize your ideas on a higher design level.
- Take a trip to phpclasses.org. Ther are a multitude of classes there
that do exactly what yours does. Maybe you can learn from it.

HTH, Michiel.

André Næss

unread,
Aug 12, 2003, 1:13:09 PM8/12/03
to
Tony Marston:

>> Keyword arguments are very practical in this type of problem, but they
>> are unfortunately not supported by PHP. A common workaround is to use
>> assoc arrays to pass the parameters, something that had felt a lot
>> cleaner had PHP supported a more practical array notation than
>> array('a'=>1, 'b'=>2, 'c'=>3).
>>
>> My favorite:
>> ['a': 1, 'b': 2, 'c': 3]
>>
>> André Næss
>
> I prefer to use the features that the language does allow and not
> waste my time in dreaming up features that it does not.

My main goal was to point out that assoc-arrays as parameters sometimes can
be an acceptable trick and it is supported by PHP, so that's not something
I'm dreaming up.

And I'd also like to point out that PHP has largely been developed as a
reply to the "dreaming" of it's users. That's probably why it's so popular!

André Næss

André Næss

unread,
Aug 12, 2003, 1:16:38 PM8/12/03
to
Tony Marston:

>> >Having a separate class for each individual database table is supposed
>> >to be a GOOD idea in OOP as it encapsulates all the information
>> >required to read/write/update/delete that particular database table.
>> >This includes a list of all fields and their characteristics so that
>> >basic validation can be done by the code which is inherited from the
>> >abstract class instead of having to write a separate set of validation
>> >code for each table.
>>
>> I disagree here. This means you write the same code for each table -
>> select, insert, update, delete again and again. But basically its
>> always the same.
>
> No I do not write the same code again and again. The code which
> handles select/insert/update/delete is inherited from the parent class
> so it is inherited by every subclass.
>

>[snip]


>
> Non-standard validation, such as 'is date A greater than date B?' is
> handled by custom code within the class for that table.

So in other words you have to rewrite those "non-standard" constraints every
time you need them. The problem is that you haven't properly decoupled two
different entities (data validation and database access). See my rather
long post which goes into this and explains how object composition rather
than inheritance leads to a much cleaner, simpler and more maintainable
solution in this particular case.

André Næss

André Næss

unread,
Aug 12, 2003, 1:22:30 PM8/12/03
to
Tony Marston:

>> 2.
>> function Database_Table ()
>> {
>> $this->tablename = 'default';
>> $this->dbname = 'default';
>> $this->rows_per_page = 10;
>>
>> $this->fieldlist = array('column1', 'column2', 'column3');
>> $this->fieldlist['column1'] = array('pkey' => 'y');
>> } // constructor
>>
>> If you this style, there won't be any reusability.
>
> Then you do not understand OO programming. All the business rules for
> a database table are maintained in a single class

The problem is that you're too hung up on *classes*, and forgetting about
their *instances* (objects)! This is fairly common for people starting out
with OOP, so you're not alone.

André Næss

André Næss

unread,
Aug 12, 2003, 1:35:40 PM8/12/03
to
Tony Marston:

> André Næss <andrena.spa...@ifi.uio.no> wrote in message
> news:<bh0j9s$bar$1...@maud.ifi.uio.no>...
>> Tony Marston:
>>
>> >> The information is typical formatting information. I think it would be
>> >> much cleaner if you allowed for two more arguments to getData() that
>> >> defined how many rows to retrieve, and what offset to start at. The
>> >> organization of data into pages belongs in presentation code.
>> >
>> > Rather have have extra arguments in my 'getData' method I have
>> > separate setters for $rows_per_page and $pageno, with a getter for
>> > $lastpage. The reason for this is that a default value for
>> > $rows_per_page can be defined in the class constructor.
>>
>> But if you say that these variables are in fact selection criteria, then
>> certainly you must agree that seeing as $where is a collection of
>> selection criteria, and it's being passed to getData(), it would be much
>> more consistent to pass them as parameters!
>
> The number of possible parameters on the getData() method is quite
> large, and as most of them are optional I find it easier to use a
> set..() method for each of these variables only when a value is
> available. As I save each object in the session array it also means
> that any value set in one operation is maintained throughout the
> session until it is changed or reset.

Well I guess that's an acceptable choice based on the fact that PHP does't
support keyword arguments.

However, I can only see that getData() supports *one* argument, $where?



> Also, the number of values I want returned may be more than, and as
> PHP only allows one value to be returned with each function call I
> save this as a separate object variable and use a get..() method it is
> needed.

A better approach would be to return a ResultObject, which you could then
query for information about the different values you want returned. This
would encapsulate these data properly, and you're going on and on about
enacpsulation, so that should appeal to you right? :)

>> KISS is a very good idea indeed. My point was that if you want to partake
>> in a community you have to follow the rules of the community, if you
>> disagree, you have to lobby your disagreement to the other members.
>
> What is obvious from the various postings in this thread is that
> different people have totally different ideas about what is *good/not
> good* OO programming.

Indeed

> Some people prefer simple solutions while others
> seem to go out of their way to invent the most convoluted solutions
> just to satisfy their personal interpretations of the *rules* of OOP.
> I follow the KISS principle.

I think everyone wants to apply KISS as much as possible, but like with so
many other things, overuse tends to be a bad thing. Design is obviously a
subjective thing, be it buildings, cars, kitchen utensils or software. But
good design has qualities, and I think Paul Graham[1] does a nice job of
describing them.



>> > You have missed the point about my abstract database class. Each
>> > database table has its own class which is a subclass of the abstract
>> > class, therefore it inherits all the properties and methods of the
>> > abstract class. Each table class therefore need only contain extra
>> > code which is specific to that class, such as a list of field names,
>> > validation rules, relationships, etc.
>>
>> Precisely. And it is this code which leads to a problematic dependency
>> between the DB and the class. I understand the point of reusing code to
>> generate SELECT/INSERT/UPDATE/DELETE statements, but you can do that
>> without having to create a class for every table you have.
>>
>

> Then where do I maintain the business rules for each individual
> database table? In a separate class?

No, in a separate object which is an instance of a some sort class that
models business rules. You can quickly turn this into an extensible type
system, which you can reuse in *all* part of your application, not just
with the DB. (For example to validate form input.)

André Næss

[1] Taste for Makers - http://www.paulgraham.com/taste.html

Jochen Daum

unread,
Aug 12, 2003, 11:06:54 PM8/12/03
to
Hi Michiel!

On Tue, 12 Aug 2003 16:40:44 +0200, Michiel
<michiel@...NO...SPAM!*.2see.nl> wrote:

(...)


>>
>> Apart from nicer presentation, paging the results allows you to reduce
>> communication with the database server; if you insist on returning the
>> entire result set from the query, and *then* choosing a subset of it
>> from the PHP code, you introduce an unnecessary layer, which can be
>> done away with entirely by using "LIMIT x, y" in the query.
>
>AND make it mysql dependent. The LIMIT clause is not widely supported.

But can be build in other database systems with nested queries. I run
such nested queries against well indexed tables in SQL Server and
Informix and it works fine.
Thats why I integrated the appropriate Query functions into my
Database Abstraction Layer.


>Besides, mysql will most probably allocate the whole result set and
>return only part of it, so it doesn't matter all that much.

I doubt that heavily. MySQL's query optimization is very good and I
don't think it would be that stupid. I'd expect this behaviour from MS
Access.

HTH, Jochen

Jochen Daum

unread,
Aug 12, 2003, 11:07:42 PM8/12/03
to
Hi Andre!

On Tue, 12 Aug 2003 17:13:09 +0000, André Næss
<andrena.spa...@ifi.uio.no> wrote:

>Tony Marston:
>
>>> Keyword arguments are very practical in this type of problem, but they
>>> are unfortunately not supported by PHP. A common workaround is to use
>>> assoc arrays to pass the parameters, something that had felt a lot
>>> cleaner had PHP supported a more practical array notation than
>>> array('a'=>1, 'b'=>2, 'c'=>3).
>>>
>>> My favorite:
>>> ['a': 1, 'b': 2, 'c': 3]
>>>
>>> André Næss
>>
>> I prefer to use the features that the language does allow and not
>> waste my time in dreaming up features that it does not.
>
>My main goal was to point out that assoc-arrays as parameters sometimes can
>be an acceptable trick and it is supported by PHP, so that's not something
>I'm dreaming up.

I think its more than a good trick.

Jochen Daum

unread,
Aug 12, 2003, 11:11:39 PM8/12/03
to
Hi tony!

On 12 Aug 2003 00:13:18 -0700, to...@marston-home.demon.co.uk (Tony
Marston) wrote:

>matty <matt...@askmenoquestions.co.uk> wrote in message news:<%1LZa.1232$z7.3...@wards.force9.net>...
>> Tony Marston wrote:
>>
>> <snip>
>>
>> > Having a separate class for each individual database table is supposed
>> > to be a GOOD idea in OOP as it encapsulates all the information
>> > required to read/write/update/delete that particular database table.
>> > This includes a list of all fields and their characteristics so that
>> > basic validation can be done by the code which is inherited from the
>> > abstract class instead of having to write a separate set of validation
>> > code for each table.
>>
>> I have to disagree with you here! Having a separate class *instance* is
>> good OO, having a separate *class* is bad OO, since you lose all the
>> potential benefits of low maintenance, etc.
>
>I disagree most strongly. I have a separate class for each database
>table as that contains the validation rules and special processing
>considerations for that table. This is called 'encapsulation' which is
>*good* OO programming. If there is only one class for ALL database
>tables then where do I put the business rules for each individual
>table? Where is the encapsulation in that idea?
>

And I put myself on matty's side. The validation rules belong to a
table, correct, but i don't need a validation rule to check for the
length of text in each class. Same with date/time entry, select boxes
for lookup etc.

Maybe have a look at the Strategy pattern and Delegation as a concept
altogether instead of the classic inheritance model of OO.


>
>> How about something like this:
>>
>> (obviously not a specific implementation, more a hypothetical description
>> of an interface)
>>
>> $tablea = new DBTable($database, $user, $password, $table);
>> foreach(array('widgetid', 'manufr', 'cost', 'colour', 'weight') as $item)
>> {
>> $tablea->AddField($item);
>> }
>> $tablea->AddConstraint('cost > 20.00');
>> $tablea->AddConstraint('colour = \'blue\'');
>> if (!array_key_exists('offset', $_GET) or !preg_match('/^[0-9]+/', $_GET['offset']))
>> {
>> $dboffset = 0;
>> }
>> $resultarray = $tablea->GetPageList($offset, $config['database']['pagelength']);
>>
>> Then you can change database, change fields, paging length, WHERE constraints, etc
>> without having to change the *class*, merely the class instance. You only have to change
>> DBTable class code if you're changing its functionality.
>>
>> Otherwise, in a system with 12 database tables, having a different class for each
>> table? That's not good.
>>
>> Matt
>
>Your idea requires too much effort. You have a generic table class
>which contains no business rules, but you have a separate object which
>creates an instance of this generic class then tells it what the
>business rules are.

Once for each page, yes.

> In my method I do not build a class that tells the
>generic class what the business rules are, I have a subclass which
>contains those rules and which inherits all the generic code from the
>base class.
>
>We both seem to have a separate class for each table, but implemented
>differently. I maintain that my method is easier.

Hmm. I actually prefer a class for all tables.

HTH, Jochen

Jochen Daum

unread,
Aug 12, 2003, 11:15:54 PM8/12/03
to
Hi Tony!
On 12 Aug 2003 00:01:06 -0700, to...@marston-home.demon.co.uk (Tony
Marston) wrote:

>Jochen Daum <joche...@cans.co.nz> wrote in message news:<h14gjv8lr2r35qdt1...@4ax.com>...
>> Hi Tony!
>> On 11 Aug 2003 03:28:11 -0700, to...@marston-home.demon.co.uk (Tony
>> Marston) wrote:
>>
>> snip
>> >
>> >Having a separate class for each individual database table is supposed
>> >to be a GOOD idea in OOP as it encapsulates all the information
>> >required to read/write/update/delete that particular database table.
>> >This includes a list of all fields and their characteristics so that
>> >basic validation can be done by the code which is inherited from the
>> >abstract class instead of having to write a separate set of validation
>> >code for each table.
>>
>> I disagree here. This means you write the same code for each table -
>> select, insert, update, delete again and again. But basically its
>> always the same.
>
>No I do not write the same code again and again. The code which
>handles select/insert/update/delete is inherited from the parent class
>so it is inherited by every subclass.

Ok, agree on that. Similar to the other thread part, we're talking
about the business rules here maybe.


>
>> >If the physical database table is changed then the class which
>> >contains information about that table is also changed. This is not a
>> >maintenance problem,
>>
>> It is, if there is a standard way to handle a varchar, or a datetime.
>
>By 'standard' processing I mean the following:-
>- for char/varchar, is it required or optional? does it exceed the max
>length?
>- for datetime, is the date portion a valid date?, is the time portion
>a valid time?
>- for numbers, is the input valid numeric? is it signed or unsigned?
>does it have too many significant digits? does it have too many
>decimal digits?
>- for key fields, is the key already in use?

Exactly. And that stuff should be handled centrally. In web pages you
might also use Lookup fields or enumerations, which come from other
(database ) tables. This can be handled by such standard ways as well.

>
>Non-standard validation, such as 'is date A greater than date B?' is
>handled by custom code within the class for that table.

Also agreed.


>
>> > it is basic common sense. If a programmer changes
>> >a database table without updating the code which accesses that table
>> >then he is a ****KING PLONKER of the first order.
>>
>> Understood.
>>
>> > In my method there
>> >is one class per table, so the changes have to be made in only one
>> >place. What could be easier than that?
>>
>> One class for all. Changes are made in a data dictionary. That the
>> approach I take daily. You can see it in the project below.
>>
>> Jochen
>
>My data dictionary is held within each table class, not in a separate
>database. I do not want the overhead of accessing a separate database
>to get at my validation rules.

Mine is in a PHP file as well. I didn't call it Data Dictionary until
recently. Only because I discovered a system called Clarion, which
does something similar, with a "local" data dictionary.

Tony Marston

unread,
Aug 13, 2003, 3:31:21 AM8/13/03
to
André Næss <andrena.spa...@ifi.uio.no> wrote in message news:<bhb19n$9sg$1...@maud.ifi.uio.no>...

> Tony Marston:
>
> > André Næss <andrena.spa...@ifi.uio.no> wrote in message
> > news:<bh0j9s$bar$1...@maud.ifi.uio.no>...

<snip>

> However, I can only see that getData() supports *one* argument, $where?

There is only one permanent argument as a lot of the other values are
entirely option and are made available by using a set..() method
before the detData() method.

An advantage I have found with this approach is I save each object in
my session array, so that when I return to an object all the previous
values held in its variables are still there, so rather than the
script which calls the getData() method having to remember all those
values so that it can pass them in the argument list, the object
itself 'remembers' all the previous values automatically and reuses
them. The calling object only has to use a set..() method on one of
these values when it wants to change it, otherwise the previous valkus
is used automatically.

> > Also, the number of values I want returned may be more than, and as
> > PHP only allows one value to be returned with each function call I
> > save this as a separate object variable and use a get..() method it is
> > needed.
>
> A better approach would be to return a ResultObject, which you could then
> query for information about the different values you want returned. This
> would encapsulate these data properly, and you're going on and on about
> enacpsulation, so that should appeal to you right? :)

That won't work as some of the values I want are not held in the
database result object.

> <snip>

> >> I understand the point of reusing code to
> >> generate SELECT/INSERT/UPDATE/DELETE statements, but you can do that
> >> without having to create a class for every table you have.
> >>
> >
> > Then where do I maintain the business rules for each individual
> > database table? In a separate class?
>
> No, in a separate object which is an instance of a some sort class that
> models business rules. You can quickly turn this into an extensible type
> system, which you can reuse in *all* part of your application, not just
> with the DB. (For example to validate form input.)
>
> André Næss

So in your approach you have a PHP script containing the validation
rules for a database table which then has to set..() these rules in a
separate object before they can be processed?

My approach is to have the validation rules for each database table
held in a separate script which just happens to be a class where those
rules can be processed in situ, therefore I do not have to waste time
in sending those rules to another object before they can be processed.
My method seems neater somehow.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 13, 2003, 3:46:49 AM8/13/03
to
ng4rrj...@rediffmail.com (R. Rajesh Jeba Anbiah) wrote in message news:<abc4d8b8.03081...@posting.google.com>...

<snip>


> ---> Contradicts what style? Where is this *style* documented?
>
> All the time, we cannot refer the ___law books___... It comes from
> the practice and excercises.

You mean personal preference. My *style* is to write simple,
efficient, maintainable, reusable code based upon decades of
experience using a variety of 2nd, 3rd and 4th generation languages.



> >All the business rules for
> > a database table are maintained in a single class, so when any
> > presentation object wants to communicate with that table it uses that
> > table's class. Thus I can have many presentation objects all reusing
> > the same table class. That is where *reusability* comes from. This is
> > the basis of the 3 tier architecture which I used in a previous
> > language.
>
> I was refering *reusabiliy* on different projects (Not on a
> single project in which your database is "foo" and table name is
> "foo").

The database name is not tied to a project, it is specified within the
class for each individual database table. A project can have many
database tables existing on more than one database.

> Also, if the class you mentioned is for single purpose, it's ok.
> But, you've written a *tutorial*. Everybody who reads the *tutorial*
> will be tempted to follow the style. If they follow the style, they
> may suffer when it comes to reusability rules on more than 1 project.

It is an example of how to use PHP's OO capabilities to produce a
reusable class (through inheritance bu subclassing) to access a
database. The fact that some people would choose a different method is
their choice. When it comes to programming there is no single *right*
way. There are methods that work and methods that don't; there are
methods which are easy to implement and methods which are complex;
there are methods which achieve a result in 10 lines of code while
others take hundreds; there are methods which use a large number of
simple components while others use a small number of complex
components. My point is that variety is the spice of life, and I have
produced sample code which works and which is simple. If you do not
like my *style* then I don't care. It is results that count.

> > > This is my point. I may be wrong though...
> >
> > You may well be!
>
> Yes... I'm wrong. But, IMO you're also not correct..

Then we agree to disagree.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 13, 2003, 3:52:43 AM8/13/03
to
André Næss <andrena.spa...@ifi.uio.no> wrote in message news:<bhb0h1$9p8$3...@maud.ifi.uio.no>...
> Tony Marston:
>
<snip>

> > Then you do not understand OO programming. All the business rules for
> > a database table are maintained in a single class
>
> The problem is that you're too hung up on *classes*, and forgetting about
> their *instances* (objects)! This is fairly common for people starting out
> with OOP, so you're not alone.
>
> André Næss

I am aware of the ifference between classes and objects, thank you
very much. If I want to access a particular database table then I
create an object (instance) from the class which contains all the
business rules for that table. I do not create an instance of a
generic class and then have to feed it the rules for the database
table I wish to access.

Tony Marston
http://www.tonymarston.net/

Tony Marston

unread,
Aug 13, 2003, 4:07:07 AM8/13/03
to
Michiel <michiel@...NO...SPAM!*.2see.nl> wrote in message news:<3f38fe40$0$49100$e4fe...@news.xs4all.nl>...
> Tony Marston wrote:

<snip>


> You've done a good job. Certainly. But.... if you learn some more about
> OOP you could use it much more effective.

More effective? In what way? Surely I have written an abstract class
which can be used to access any database table, where subclasses are
created to contain the specific business rules for individual database
tables. What can be more effective than that?

> And to be honest... a database
> access layer is not the most difficult thing to write.

Yet as can be seen from this thread everybody seems to have a
different way of writing one.

> You can afford to
> make some design errors and still have a useful class.

That is true for all software development.

> If you start
> writing more complex software (probably soon) you would get into trouble
> if you keep coding this style.

I have been using this style for over a year and rather than cause
problems it has provided me with a large chunk of reusable code which
saves a lot of development time.

> My advice:
> - Learn some more about 'design patterns'. They can help you.

Some people's ideas on design patterns are just as screwy as their
ideas on OOP.

> - Learn UML (unified modelling language), it helps you to first
> conceptualize your ideas on a higher design level.

I have been designing and writing for over 20 years and I see no
advantage in using UML. In fact on one project I worked on UML turned
out to be a great way to waste time.

> - Take a trip to phpclasses.org. Ther are a multitude of classes there
> that do exactly what yours does. Maybe you can learn from it.

I found too many classes with too many different styles, which is why
I decided to write my own class based on the sucessfull implementation
of the 3 tier architecture in another language which had a separate
service component for each table in the database, and which contained
all the business rules for that database table. All I did was change
'service component' into 'class' and it has worked very well.

Tony Marston
http://www.tonymarston.net/

André Næss

unread,
Aug 13, 2003, 3:40:23 PM8/13/03
to
Tony Marston:

> André Næss <andrena.spa...@ifi.uio.no> wrote in message
> news:<bhb0h1$9p8$3...@maud.ifi.uio.no>...
>> Tony Marston:
>>
> <snip>
>
>> > Then you do not understand OO programming. All the business rules for
>> > a database table are maintained in a single class
>>
>> The problem is that you're too hung up on *classes*, and forgetting about
>> their *instances* (objects)! This is fairly common for people starting
>> out with OOP, so you're not alone.
>>
>> André Næss
>
> I am aware of the ifference between classes and objects, thank you
> very much.

That's fine. What I'm saying is that you haven't yet appreciated the power
of object composition, and because of this you apply inheritance too much.

André Næss

André Næss

unread,
Aug 13, 2003, 6:56:42 PM8/13/03
to
Tony Marston:

> André Næss <andrena.spa...@ifi.uio.no> wrote in message
> news:<bhb19n$9sg$1...@maud.ifi.uio.no>...
>> Tony Marston:
>>
>> > André Næss <andrena.spa...@ifi.uio.no> wrote in message
>> > news:<bh0j9s$bar$1...@maud.ifi.uio.no>...
>
> <snip>
>
>> However, I can only see that getData() supports *one* argument, $where?
>
> There is only one permanent argument as a lot of the other values are
> entirely option and are made available by using a set..() method
> before the detData() method.
>
> An advantage I have found with this approach is I save each object in
> my session array, so that when I return to an object all the previous
> values held in its variables are still there, so rather than the
> script which calls the getData() method having to remember all those
> values so that it can pass them in the argument list, the object
> itself 'remembers' all the previous values automatically and reuses
> them. The calling object only has to use a set..() method on one of
> these values when it wants to change it, otherwise the previous valkus
> is used automatically.

That sounds very strange. Objects have states, sessions are a way to
maintain state. So your maintaining the state of something that already has
a state, or something like that.

The "remembering" you're talking about is just code, and code is very static
in nature. If you in your code write:

getData("color=red AND buildyear > 1999", 10, 10)

Then certainly the arguments won't change between runs. The code "remembers"
them, if you like. And if you use session you still have to initialize them
at some point anyway, and that is done through code!

Likewise if you write
$sometable->setPageCount(10);

Every time this script executes the object will have the same state, so I
can't understand why you need to stuff it into a session.

But I might be misunderstanding you, could you possibly supply an example
where using sessions is beneficial in the way you're describing?

A little tip: you don't have to serialize data that you stuff into the
_SESSION array, PHP takes care of that for you. See the paragraph just
after the "Caution" block here: http://www.php.net/session



>> > Also, the number of values I want returned may be more than, and as
>> > PHP only allows one value to be returned with each function call I
>> > save this as a separate object variable and use a get..() method it is
>> > needed.
>>
>> A better approach would be to return a ResultObject, which you could then
>> query for information about the different values you want returned. This
>> would encapsulate these data properly, and you're going on and on about
>> enacpsulation, so that should appeal to you right? :)
>
> That won't work as some of the values I want are not held in the
> database result object.

The object will contain what you define it to contain, you have to model it
for your needs of course! One of the points of OO is that you model the
world according to what suits your problem (abstraction). You don't have to
*mirror* it.

>> <snip>
>
>> >> I understand the point of reusing code to
>> >> generate SELECT/INSERT/UPDATE/DELETE statements, but you can do that
>> >> without having to create a class for every table you have.
>> >>
>> >
>> > Then where do I maintain the business rules for each individual
>> > database table? In a separate class?
>>
>> No, in a separate object which is an instance of a some sort class that
>> models business rules. You can quickly turn this into an extensible type
>> system, which you can reuse in *all* part of your application, not just
>> with the DB. (For example to validate form input.)
>>
>> André Næss
>
> So in your approach you have a PHP script containing the validation
> rules for a database table which then has to set..() these rules in a
> separate object before they can be processed?

Say I wanted to talk to the table "cars". I'd compose an object by creating
an instance of a Table class and add rules represented as objects to it. Of
course, the business rules should be taken care of by the DBMS, not your
application code, but unfortunately that is not completely possible in
current SQL systems. So let's take a simple rule like "the name of the car
should be at least 1 character, and no more than 32". To model this I'd
create a String object that has this limitation built in, and link it to
the 'name' field in the Table object. Other common data types are Number,
Date, File, Time, Creditcard etc.

These are fairly simple type validations, but they should go a long way.
You'll probably also want to have some sort of generic Rule object for rare
cases where none of the available objects suffice, and you don't want to
create a new class. It is of course very important that these things are
implemented separately, so that they can be reused whenever you need to
validate any data.

But the database can enforce a lot of constraints, and one should really put
as much business logic into the database as possible because:

* It's less work
* It's safer from bugs, because the DBMS developers have (hopefully) tested
it properly.
* It's most likely faster.

I see that you among other things have code to enforce foreign key
constraints, but wouldn't it be much better not to need that code at all?



> My approach is to have the validation rules for each database table
> held in a separate script which just happens to be a class where those
> rules can be processed in situ, therefore I do not have to waste time
> in sending those rules to another object before they can be processed.
> My method seems neater somehow.

What sort of time are you wasting? Are you saying that writing a whole new
class is better than instantiating a few objects?

The point here is that you have to think about what is static and what is
dynamic in your application. Now, the concept of a database table is
certainly static, and so are data types and the concept of a constraints.
But databases are dynamic, in any given application you will have different
databases, with different data types and different constraints. In general
you want to use classes for that which is static, and hence not application
specific or frequently changing, and objects for the other things. Abstract
concepts are classes, their instances are objects. IMO The table 'cars' is
not an abstract concept but an object in the world.

I guess this boils down to matter of personal taste. But one of the
hallmarks of good designers is that they have a gut-feeling for what's good
design and what's not, and I think that if you ask some good designers they
will tell you that an approach which uses instances of a single Table class
is better than one which requires the declaration of a new class for each
new table. A good advice is probably to pretend there is a sort of tax on
creating new classes.

And just to make sure we're not in total disagreement, I think you are
absolutely right in what you say in the bullet-list in the "Background"
section.

André Næss

R. Rajesh Jeba Anbiah

unread,
Aug 14, 2003, 3:52:05 AM8/14/03