Объектная парадигма для PHP, практика в дизайн


Я создал и я управляю точки продажи веб-приложение, построенное на PHP, которая до сих пор не имеют четких руководящих принципов или методологии разработки; операции полностью процедурный. В свою очередь, потому что отдел, который использует это просит новых и разных функций, как это в Лас-Вегасе "шведский стол", программное обеспечение превратилось в беспорядок, который я в ужасе (не смотри ей в глаза). К счастью, я единственный разработчик и поэтому никто не должен чувствовать себя гнев зверя я создал.

Мне всегда было трудно уложить в голове по ООП, но я думаю, что я наконец начинаю понимать весь смысл позади инкапсуляция методы, защиты полей, и наследование классов. Это подводит меня к моему вопросу: учитывая схемы объекта, размещенные ниже, я делаю это право? Он работает, как он должен и не возвращает никаких ошибок, но с точки зрения дизайна объект, я чувствую, как олененок с дрожащими ногами, не зная мира вокруг меня.

Чтобы быть немного более конкретным, я должен иметь отдельный класс, который инкапсулирует параметры в MySQL - а где он должен быть включен/наследство, если много занятий ребенка, возможно, даже на отдельных запросов к серверу, понадобится?

Если эти два класса быть один? Я думал, что отделить их ради длины файла - это излишняя размер файла хороший показатель, когда класс может нужно расстаться?

Аннотация, закрытая, охраняемая - я понимаю, как это работает в буквальном поведение, но в отношении использования, я просто качается в темноте. Кто-нибудь пролить свет на то, что я сделал и есть ли смысл? Я думаю, что это суммирование мои страхи и опасения. Вот код в вопрос - Ваши ответы помогут мне редизайн/рефакторинг все, что я провел последние 6 месяцев.

filterReports.class.php

date_default_timezone_set('America/Chicago'); // For use by 'date()' and 'strtotime()'

/*
*   First, we will create our appropriate file names for the dates in question,
*   then we will determine if today is a day to run said reports. If today is in fact
*   a fine day to create a report, we should then check to see if the desired
*   report has already been created. If it has not, we will create and save it.
*/

abstract class filterReports
{

    protected $reportFilenames = array(); // Store all file names in array, because it's fun
    protected $reportDirs = array(
        'daily-orders' => 'reports/daily/orders/',
        'weekly-orders' => 'reports/weekly/orders/',
        'monthly-orders' => 'reports/monthly/orders/',
        'daily-volume' => 'reports/daily/volume/',
        'weekly-volume' => 'reports/weekly/volume/',
        'monthly-volume' => 'reports/monthly/volume/',
    ); // Folders where we plan to store these reports

    protected function createFilenames()
    {

        // Comprehensive Order Data
        $this->reportFilenames['daily-orders']      = 'store-report-'
                                                    . date('Ymd', strtotime('-1 day'))
                                                    . '.csv'; // Yesterday's Report
        $this->reportFilenames['weekly-orders']     = 'store-report-'
                                                    . date('Ymd', strtotime('-8 days'))
                                                    . '-'
                                                    . date('Ymd', strtotime('-1 day'))
                                                    . '.csv'; // Last 7 Days
        $this->reportFilenames['monthly-orders']    = 'store-report-'
                                                    . date('Ymd', strtotime('first day of last month'))
                                                    . '-'
                                                    . date('Ymd', strtotime('last day of last month'))
                                                    . '.csv'; // Last Month

        // General Product Volume Data
        $this->reportFilenames['daily-volume']      = 'store-volume-'
                                                    . date('Ymd', strtotime('-1 day'))
                                                    . '.csv'; // Yesterday's Report
        $this->reportFilenames['weekly-volume']     = 'store-volume-'
                                                    . date('Ymd', strtotime('-8 days'))
                                                    . '-'
                                                    . date('Ymd', strtotime('-1 day'))
                                                    . '.csv'; // Last 7 Days
        $this->reportFilenames['monthly-volume']    = 'store-volume-'
                                                    . date('Ymd', strtotime('first day of last month'))
                                                    . '-'
                                                    . date('Ymd', strtotime('last day of last month'))
                                                    . '.csv'; // Last Month

    }

    protected $reportsToCreate = array();   // Based on what day it is, a different report may need to be created

    protected function chooseReports()
    {

        $this->reportsToCreate['daily-orders'] = TRUE; // Because 'every day' occurs every day.
        $this->reportsToCreate['daily-volume'] = TRUE;

        if (date('N', time()) == '1') { // If today is Monday, create weekly report
            $this->reportsToCreate['weekly-orders'] = TRUE;
            $this->reportsToCreate['weekly-volume'] = TRUE;
        } else {
            $this->reportsToCreate['weekly-orders'] = FALSE;
            $this->reportsToCreate['weekly-volume'] = FALSE;
        }

        if (date('j', time()) == '1') { // If today is the first day of the month, create monthly report
            $this->reportsToCreate['monthly-orders'] = TRUE;
            $this->reportsToCreate['monthly-volume'] = TRUE;
        } else {
            $this->reportsToCreate['monthly-orders'] = FALSE;
            $this->reportsToCreate['monthly-volume'] = FALSE;
        }

    }

    protected $reportsExist = array(); // Now let's see which reports have already been created

    protected function searchReports()
    {

        foreach ($this->reportsToCreate as $key => $val) {

            if ($val != FALSE) {                
                if (!file_exists($this->reportDirs[$key] . $this->reportFilenames[$key])) {
                    $this->reportsExist[$key] = FALSE;
                } else {
                    $this->reportsExist[$key] = TRUE;
                }
            }           

        }

    }

}

manageReports.class.php

include('filterReports.class.php');

/*
*   As an extension of the previous class 'filterReports', if a desired report has
*   not been found, we will create and save it.
*/

class manageReports extends filterReports
{

    public $newReport;

    private $dbConfig = array();
    private $con;   

    private function dbParams() // This should all probably go somewhere else, but I haven't decided where just yet
    {

        $this->dbConfig = array(
            'host' => 'hostname',
            'user' => 'username',
            'pass' => 'password',
            'name' => 'database',
        );
        $this->con = mysql_connect(
            $this->dbConfig['host'],
            $this->dbConfig['user'],
            $this->dbConfig['pass']
        ) or die('MySQL Error: ' . mysql_errno() . ' - ' . mysql_error());

    }

    private function createDailyOrdersReport() // Collect data and build the report body
    {

        // Do things to create $dataHeading and $dataContent strings
        $this->newReport = $dataHeading . $dataContent;

    }

    private function createDailyVolumeReport()
    {
        $this->newReport = $dataHeading . $dataContent;
    }

    private function createWeeklyOrdersReport()
    {
        $this->newReport = $dataHeading . $dataContent;
    }

    private function createWeeklyVolumeReport()
    {
        $this->newReport = $dataHeading . $dataContent;
    }

    private function createMonthlyOrdersReport()
    {
        $this->newReport = $dataHeading . $dataContent;
    }

    private function createMonthlyVolumeReport()
    {
        $this->newReport = $dataHeading . $dataContent;
    }

    private function writeReport($key)
    {

        // Save the report to its appropriate folder
        $writeReportName = $this->reportDirs[$key] . $this->reportFilenames[$key]; // I don't know why this works, seems to me to be out of scope for these array fields
        $writeReportOpen = fopen($writeReportName, 'w');
        fwrite($writeReportOpen, $this->newReport) or die('Unable to write file: ' . $writeReportName);
        fclose($writeReportOpen);

    }

    public function createReports() // Finally, resolve which reports should be created - then create them.
    {

        parent::createFilenames();  // Create the report file names
        parent::chooseReports();    // Decide whether a report should be run
        parent::searchReports();    // Find out if the report exists already

        foreach ($this->reportsExist as $key => $val) { // Any reports that should be created today, T or F for 'exists'
            if ($val != TRUE) {
                if ($key = 'daily-orders') {
                    $this->createDailyOrdersReport();
                    $this->writeReport($key);
                }
                if ($key = 'daily-volume') {
                    $this->createDailyVolumeReport();
                    $this->writeReport($key);
                }
                if ($key = 'weekly-orders') {
                    $this->createWeeklyOrdersReport();
                    $this->writeReport($key);
                }
                if ($key = 'weekly-volume') {
                    $this->createWeeklyVolumeReport();
                    $this->writeReport($key);
                }
                if ($key = 'monthly-orders') {
                    $this->createMonthlyOrdersReport();
                    $this->writeReport($key);
                }
                if ($key = 'monthly-volume') {
                    $this->createMonthlyVolumeReport();
                    $this->writeReport($key);
                }
            }
        }

    }

}

Наконец, я делаю это, чтобы сделать его пойти.

include('manageReports.class.php');

$initReports = new manageReports;
$initReports->createReports();

Я превентивно ценю любую помощь вы можете предоставить, как он, несомненно, сделает меня менее фиктивных веб-разработчика.

Редактировать: еще один вопрос я просто подумал, что в после-думал; я должен даже беспокоиться объявив мои поля и методы в filterReports как защищены, видя, как будто нельзя создать экземпляр этого класса в первую очередь?

Редактировать: я сделал некоторые изменения в мой код, основанный на ответах. Сейчас, забудьте о выше двух классов - вот мой новый код. Первый класс создает экземпляр каждого моего доклада генерации суб-классы и выполняет публичные функции, содержащиеся в каждом из них. Второй класс-это один класс генерации отчетов.

manageReports.class.php

include('store/library/reports/dailyOrdersReport.class.php');

/*
* Having included the desired reporting classes,
* we now need a uniform process for access and
* execution of these classes.
*/

class manageReports
{

    private $reports = array();

    public function __construct()
    {

        $this->createReports();

    }

    private function createReports()
    {

        $this->createReport('dailyOrdersReport');

    }

    private function createReport($class)
    {

        $this->reports[] = new $class;

    }

    public function go()
    {

        foreach ($this->reports as $report) {
            $report->execReport();
        }

    }

}

dailyOrdersReport.class.php

include('store/library/dbConfig.class.php'); // May need these parameters for dependent methods

/*
* Validates the need for specified report creation,
* and if true - does so.
*/

class dailyOrdersReport extends dbConfig
{

    private $newReport; // Variable to store report data

    private $reportPath;
    private $reportName;

    private $reportTestResult = FALSE;

    public function __construct() // Preprocess validation answers, "Should we create this report?"
    {

        parent::__construct(); // MySQL Parameters

        $this->reportPath   = 'store/reports/daily/orders/';
        $this->reportName   = 'store-orders_'
                            . date('Ymd', strtotime('-1 day'))
                            . '.csv';
        $this->reportTest();

    }

    private function reportTest() // We don't need to test against the date for this report, just if it's already been created
    {

        if (!file_exists($this->reportPath . $this->reportName)) {
            $this->reportTestResult = TRUE;
        } else {
            return;
        }

    }

    private function createReport()
    {

        // About 100 lines of csv report generating madness
        $this->newReport = $dataHeading . $dataContent;

    }

    private function writeReport()
    {

        // Save the report to its appropriate folder
        $writeReportName = $this->reportPath . $this->reportName;
        $writeReportOpen = fopen($writeReportName, 'w');
        fwrite($writeReportOpen, $this->newReport) or die('Unable to write file: ' . $writeReportName);
        fclose($writeReportOpen);

    }

    public function execReport()
    {

        if ($this->reportTestResult) { // Evaluates to 'true' if report aught be generated and saved to file
            $this->createReport();
            $this->writeReport();
        } else {
            return;
        }

    }

}

Еще раз курок.

error_reporting(E_ALL);

date_default_timezone_set('America/Chicago'); // For use by 'date()' and 'strtotime()'

include('store/library/manageReports.class.php');

$manageReports = new manageReports;
$manageReports->go();

Пока это совершенное, или есть еще миль, чтобы пойти прежде чем я спать?



767
8
задан 14 февраля 2011 в 04:02 Источник Поделиться
Комментарии
2 ответа

Когда я вижу кучу повторяется , если испытания значение нескольких констант, я думаю, "сделать эти классы". У вас есть отчет базового класса кричать, чтобы выйти с одного подкласса на каждый тип отчета. Если вы считаете, что каждого доклада в целом, вы начнете видеть, какие операции он должен получить поддержку:


  • Решить, если он должен быть запущен с учетом даты

  • Проверьте, существует ли он на диске

  • Генерировать имя файла и название

  • Извлечение данных из MySQL в текстовый блок

  • Запишите себе на диск

Здесь представлены вышеуказанные требования в абстрактный базовый класс, один предназначен быть продлен подклассами, чтобы заполнить детали.

abstract class AbstractReport {
private $directory;
private $date;

public function __construct($directory, $date) {
$this->directory = 'reports/' . $directory;
$this->date = $date;
}

public abstract function getTitle() ;
public abstract function getFileName() ;
public abstract function isNeeded() ;

public function hasBeenRun() {
return file_exists($this->key . $this->getFileName();
}

public function runIfNeeded() {
if ($this->isNeeded() && !$this->hasBeenRun()) {
$this->run();
}
}

public function run() {
$this->connectToDatabase();
file_put_contents($this->getTitle(), $this->buildReport());
}

protected function connectToDatabase() {
// ... mysql_connect() ...
}

protected abstract function buildReport() ;

protected function formatDate($offset, $format='Ymd') {
return date($format, strtotime($offset, $this->date));
}

Вот пример подкласс на одном из отчетов.

class DailyOrdersReport extends AbstractReport {
public function __construct($date) {
parent::__construct('daily/orders/', $date);
}

public function getTitle() {
return 'Daily Orders';
}

public function getFileName() {
return 'store-report-' . $this->formatDate('-1 day');
}

public function isNeeded() {
return true; // or use $this->date to make determination
}

protected abstract function buildReport() {
// ... pull data from database and return formatted text ...
}
}

Надеюсь, это поможет вам начать на некоторых OOness. :) Я настоятельно рекомендую книгу Чистый код, так как это большая помощь, как вы работаете, чтобы ответить на эти вопросы для себя.

Редактировать как вы пишите доклад классов, вы можете обнаружить, что все заказы, отчеты поделиться некоторыми функциональность в общий объем отчета не и наоборот. Если это важно, вы можете создать более абстрактные классы AbstractOrdersReport и AbstractVolumeReport. Если единственная разница между временными интервалами нужные передают запросы к базе данных, вы могли бы получить много из этого.

Конечно, что сейчас отсутствует способ запуска отчетов! Ниже приводится более процедурным, чем ОО, но это может быть вызвано файла или что-то подобное.

class ReportManager {
private $reports = array();

public function __construct($date) {
$this->date = $date;
$this->createReports();
}

public function createReports() {
// could read these from disk or a table
$this->createReport('DailyOrders');
$this->createReport('DailyVolume');
$this->createReport('WeeklyOrders');
$this->createReport('WeeklyVolumn');
$this->createReport('MonthlyOrders');
$this->createReport('MonthlyVolumn');
}

protected function createReport($class) {
$this->reports[] = new $class($this->date);
}

public function runIfNeeded() {
foreach ($this->reports as $report) {
$report->runIfNeeded();
}
}

public function run() {
foreach ($this->reports as $report) {
$report->run();
}
}
}

// ... and to kick it off ...

$date = time();
$manager = new ReportManager();
$manager->runIfNeeded();

7
ответ дан 15 февраля 2011 в 05:02 Источник Поделиться

Первое замечание заключается в том, что у вас есть шесть функций в manageReports , которые идентичны, каждый из которых называют седьмым, createReports. Хотя я понимаю, что ты хочешь иметь логическую функцию именования, учитывая, что у вас вообще с логикой как, когда каждая программа должна быть расположена в chooseReports и createReports функции, вы могли бы также бросить все ненужные.

Для более общего ответа, не похоже, что эти два класса должны быть отделены. Длина класса-это не главное; вы хотите, чтобы группа вещей разумно. Вообще говоря, вы не разделяете только тогда, когда ты совершаешь более конкретным экземпляром суперкласса. В вашем случае, если вы обнаружите, что различные типы отчетов требуют разной функциональности, могли бы подкласс различные типы отчетов.

0
ответ дан 14 февраля 2011 в 07:02 Источник Поделиться