PHP 摘要;这是使用抽象类的正确方法吗?

发布于 2024-12-27 06:43:48 字数 4136 浏览 4 评论 0原文

我只是想知道我是否走在正确的道路上。将大多数函数抽象化似乎没有必要,因为数据几乎相同。这是无效的方法吗?

<?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);
        }
    }

它所做的只是打印出具有特定查询的任务,并返回一个关联数组。

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> — '.$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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

栩栩如生 2025-01-03 06:43:49

当从抽象类继承时,父类声明中标记为抽象的所有方法都必须由子类定义;此外,这些方法必须以相同(或较少限制)的可见性来定义。例如,如果抽象方法定义为 protected,则函数实现必须定义为 protected 或 public,但不能定义为 private。此外,方法的签名必须匹配,即类型提示和所需参数的数量必须相同。 这也适用于 PHP 5.4 的构造函数。在 5.4 之前,构造函数签名可能有所不同。
--php.net

在您的构造函数的实现签名中是不同的。 。

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, i.e. 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..

很酷又爱笑 2025-01-03 06:43:49

这是一个使用抽象类的真实示例:小部件。

我有一个小部件模型,它具有创建、编辑、保存或渲染小部件所需的大部分功能。然而,有两个基本指标表明我需要这个类是抽象的:

  1. 每个小部件实现必须定义一个 edit() 方法和一个 render() 方法,如照片小部件具有不同的属性,并且应以与推文小部件不同的方式显示。
  2. 我不需要“普通”Widget 实例。它必须始终是该类的子实现。

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.
下雨或天晴 2025-01-03 06:43:48

“这是无效的做法吗?”

不,您的代码正确使用了抽象。您可以集中通用逻辑,但是通过将父类声明为抽象类,您将强制通过子类完成该类的实例化(扩展您的抽象父类),这效果很好。

一条建议:

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

以这种方式声明成员变量会破坏封装。我建议您通过调用代码而不是在构造函数中分配这样的成员变量。

"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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文