11

I'm a relative newcomer to PHP, and I'm figuring out the best way to implement some database access code. I'm trying to create some simple database access objects -- each table gets its own class, each instance of the class represents a row in the table, you know the drill.

I have code that seems to be working, but some of what I've seen online makes me worry that my approach may be wrong-headed somehow. And since "Can I do this?" and "SHOULD I do this?" are two different questions, I was hoping some PHP vets could chime in.

My current strategy is to create a base-level abstract Table class that contains all the common code and then have each class representing an individual table extend it.

My main concern is this code:


abstract class Table {
    protected abstract static function get_fields();
    protected abstract static function get_primary_key();
    protected abstract static function get_table_name();

The idea is that each implementing class will define the field names, the primary key(s), the table name, etc., and then the Table class will use those functions to fill in specific blanks, like so:


    static function insert($values) {
        $field_list = array();
        $value_list = array();
        foreach (static::get_fields() as $field_name) {
            if (isset($values[$field_name])) {
                $field_list[] = $field_name;
                $value_list[] = self::escape($values[$field_name]);
            }
        }
        $field_string = join(", ", $field_list);
        $value_string = "'" . join("', '", $value_list) . "'";

        $sql = "insert into " . static::get_table_name() . " ($field_string) values ($value_string)";

As you can see, the key is that I'm accessing those static abstract functions by prefacing them with static::. And as far as I can tell, it's working!

However, the accepted answer to this question indicates that abstract static functions still aren't allowed in 5.3.

So, I'm trying to figure out what to make of this. Is the answer wrong -- are abstract static functions now considered perfectly legal PHP code? Am I doing something inadvisable in my code? Is there another approach I ought to consider?

13
  • 1
    If you say "you know the deal", I know one thing for sure: The deal is to not use static functions for that. If you think it it's, it must be the null-checkers deal, because static functions do not work well with inheritance which you like to make use of. Additionally I suggest you to read the PoEEA, I mean, you know the deal kind of book, right? Commented May 24, 2012 at 16:39
  • 4
    @hakre: Where is this hostility and condescension coming from? "You know the drill" was a reference to a fairly standard approach to modeling database contents that I didn't think was worth belaboring. Commented May 24, 2012 at 18:56
  • Please give reference that what you describe is a fairly standard approach. Commented May 24, 2012 at 19:33
  • 1
    There are a number of ORM frameworks available for PHP, including (but not limited to) Doctrine, Zend Framework and Propel. This is an extraordinarily complicated wheel; are you sure you want to re-invent it? Commented May 24, 2012 at 21:32
  • 5
    @Phoenix: Honestly? Lord, no. But my options are unpleasant; we don't have a proper sysadmin for the production server, and the PHP install that's there ... I'll be nice and call it "feature-light." Installing anything interesting is going to be way too white-knuckle for my liking. I'd rather make my own wheel, imperfect though it may be, than keep dragging around a sled. Commented May 24, 2012 at 21:41

2 Answers 2

17

Here's your example

abstract class Table implements iTable {

    public static function insert() {
        $class = get_called_class();
        $sql = 'INSERT INTO '.$class::get_class_name();
        echo $sql;
    }    

}

interface iTable {
    static function get_class_name();
}    


class ConcreteTable extends Table
{
    public function ConcreteTable() {}

    static function get_class_name() {
        return 'ConcreteTable';
    }

}

$t = new ConcreteTable();
$t::insert();

This example respects object paradigm, and you're sure it'll work even if PHP stop support late static bindings (which is a PHP specificity, I think)

Edit: What both answers show is that it's unknown that an abstract class introduces an interface as well for classes extending from it. Following the template pattern, this is possible in PHP even with static functions (albeit for a good reason that gives you strict standard warnings). The proof of concept:

abstract class Table
{
    abstract static function get_class_name();
    public static function insert() {
        printf('INSERT INTO %s', static::get_class_name());
    }    

}

class ConcreteTable extends Table
{
    public static function get_class_name() {
        return 'ConcreteTable';
    }
}

ConcreteTable::insert();

If you remove the static keywords here, you actually will get useful (and a standard way of doing things) code:

abstract class Table
{
    protected $table = NULL;
    public function insert() {
        printf('INSERT INTO %s', $this->table);
    }    

}

class ConcreteTable extends Table
{
    protected $table = 'ConcreteTable';
}

$table = new ConcreteTable();
...
$table->insert();
Sign up to request clarification or add additional context in comments.

4 Comments

Hmm, why is there the obviously superfluous new in there - all you need is a string, e.g. $t = 'ConcretTable'; Why don't you just make this dependent on some function name read with __FUNCTION__ constant? Or even more common: Add the table name as a protected property (or the SQL query)?
Inviting an interface to the party appears to give me the behavior I'm looking for without any logical paradoxes cluttering my code. You have my thanks. :-)
@hakre : the new is just a Java habit
get_called_class() can replace the need to name the table that the class represents. So then you can have a getTableName() that returns get_called_class(), which can be overridden by individual classes to customize table name
7

An abstract function will never be static, in any kind of language.

A static function provide a functionality, even if there is no instance.

An abstract function doesn't provide any functionnality.

Logically, you can't use an abstract static function, which would --ALWAYS AND NEVER-- provide a functionnality.


B extends A

When you call a static function in B context, it'll be runned in A context (cause of static state).

But, in A context, this same function is abstract, an you're not allowed to call it.

9 Comments

So, that would be a "yes" to the question of whether I'm doing something inadvisable. Do you have any insight into why PHP seems to be letting me get away with it anyway, or suggestions for an alternate approach that's less paradoxical?
You're using the object paradigm wrong. I agree with the abstract keyword, but those 3 functions will always work on instances, they shouldn't be static.
Why shouldn't they be static? The list of fields for the User object will remain consistent across all User objects; it's not dependent on an instance. Similarly, I'd think I should be be able to call "insert" or "select" on the class rather than an instantiated object.
Your static functions, like insert, should only be runned in B classes. Why put a static insert function in A context, if you'll never call it (and never can) ?
Because the code for that insert function is fundamentally the same across all the B classes -- all that changes are the name of the table and the names of the fields. An inheritance model makes perfect sense to me here. Is there a more logically sound approach you feel I'm overlooking?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.