简体   繁体   中英

PHP Abstract ; Is this the right way to use an abstract class?

I just want to know if I'm on the right path. Making most functions abstract didn't seem necessary as the data is just about the same. Is this an invalid approach?

<?php

    abstract class Model_Tasks {

        /**
         * Database object
         *
         * @access  protected
         */
        protected $db;

        /**
         * User ID
         *
         * @access  protected
         */
        protected $uid;

        /**
         * Data array
         *
         * @access  protected
         */
        protected $data;

        /**
         * SQL Query
         *
         * @access  protected
         */
        protected $query;

        /**
         * __construct
         *
         * @access  protected
         */
        protected function __construct($query) {
            $this->db = Model_DB::getInstance();
            $this->uid = $_SESSION['uid'];

            $this->query = $query;
            $this->getTasks();
        }

        /**
         * getTasks
         *
         * @param   string
         * @access  abstract protected
         */
        protected function getTasks() {
            $result = $this->db->prepare($this->query);
            $result->execute(array(
                ':uid' => $this->uid
            ));
            $this->data =& $result->fetchAll();
            $this->taskCount = $result->rowCount();
        }

        /**
         * constructTask
         *
         * Build the HTML of a task
         *
         * @param   int
         * @param   int
         * @param   string
         * @param   string
         * @access  protected
         */
        protected function constructTask(
            $id, $cost, $title, $checked = 0
        ) {
            $cost = money_format('$%i', $cost);
            $title = stripslashes($title);

            return '
                <label class="task">
                    <input type="checkbox" name="done[]" rel="'.$id.'" '.($checked?'checked="checked"':'').' />
                    <code>'.$cost.'</code> &mdash; '.$title.'
                </label>'."\n";
        }

        /** 
         * generateOutput
         *
         * Call by key [pending, completed] and return the constructed tasks
         *
         * @param   bool
         * @access  final public
         */
        final public function generateOutput($checked) {

            try {
                if(!is_bool($checked)) throw new Exception('generateOutput must contain a boolean variable');

                if(!isset($this->data)) throw new Exception('Array has not been set.');
                else $data = $this->data;
            } catch(Exception $e) {
                die('<pre>'.$e->getMessage().'<hr />'.$e->getTraceAsString());
            }

            if(is_array($data)): foreach($data AS &$r)
                $str .= $this->constructTask($r['id'], $r['cost'], $r['title'], $checked);

            else:
                $str = '<label class="tasks"></label>';

            endif;

            return $str;
        }
    }

    // ------------------------------------------------------------------------

    /**
     * pendingTasks
     *
     * @access  public
     */
    class pendingTasks extends Model_Tasks {

        public $taskCount;

        public function __construct() {
            $query = '
                SELECT id, title, cost
                FROM tasks
                WHERE (
                    status IS FALSE
                    AND uid = :uid
                ) ORDER BY cost DESC
            ';

            parent::__construct($query);
        }
    }

    /**
     * completedTasks
     *
     * @access  public
     */
    class completedTasks extends Model_Tasks {

        public function __construct() {
            $query = '
                SELECT id, title, cost
                FROM tasks
                WHERE (
                    status IS TRUE
                    AND uid = :uid
                ) ORDER BY id DESC
                LIMIT 7
            ';

            parent::__construct($query);
        }
    }

All it does is to print out a task with a specific query, and return an associative array.

"Is this an invalid approach?"

No. Your code is using abstract correctly. You are able to centralize common logic, but by declaring the parent class as abstract, you are forcing the instantiation of the class to be done via a child class (extends your abstract, parent class), which works well.

Piece of advice:

$this->uid = $_SESSION['uid'];

Declaring member variables in this fashion breaks encapsulation. I'd advise you to assign member variables like this via your calling code, and not in your constructor.

When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility. For example, if the abstract method is defined as protected, the function implementation must be defined as either protected or public, but not private. Furthermore the signatures of the methods must match, ie the type hints and the number of required arguments must be the same. This also applies to constructors as of PHP 5.4. Before 5.4 constructor signatures could differ. -- php.net

In your implementation signature of the constructors is different..

Here's a real-world example of a time to use abstract classes: widgets.

I have a widget model that has MOST of the functionality needed to create, edit, save, or render a widget. However, there are 2 basic indicators that I need this class to be abstract:

  1. Each widget implementation MUST define an edit() method and a render() method, as a photo widget has different properties and should be displayed differently from a tweet widget.
  2. I have no need for a "plain" Widget instance. It must always be a child implementation of the class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM