5

请参阅下面的编辑

我正在尝试深入研究 PHP 中的 OOP 开发,但我真的开始感到头痛或溃疡。我只是无法理解它,部分对我来说似乎太不合逻辑了,我不知道从哪里开始,这真的让我很沮丧,因为我相信努力学习它是值得的,它为我提供了更好的概述关于我的代码。

昨天我花了一整天的时间在互联网上搜索实例和解释性文章,但现在我的感觉只会让我更加困惑。我需要一些实用的技巧,而不是像这样的例子


class person {
     var $name;
     function set_name($new_name) {
          $this->name = $new_name;
     }
     function get_name() {
          return $this->name;
     }
}
$stefan = new person();
$jimmy = new person;

$stefan->set_name("Stefan"); $jimmy->set_name("Jimmy");

echo "Stefan's full name: " . $stefan->get_name(); echo "Jimmy's full name: " . $jimmy->get_name();

像这样的例子让我质疑为什么我不应该(因为它都在同一页面中定义)只是做

$name = "Stefan"; 
echo "Stefan's full name: ".$name;

如果你问我,更短(更少的代码)更明显?

诺到我的项目。

我想做的是一个简单的投资组合网站。因此我只需要 4 个页面,一个主页,一个信息页面,一个关于我的工作的页面和一个联系表。我使用三个表clients,我想在我content工作页面上使用它们。media

我正在考虑我的结构并想出了(在我的脑海中,不知道如何实现它)类似的东西

class Database{}
class Content extends Database{}
     function showMenu(){}
     function showContent{}
class Clients extends Database{}
     function showClientList{}
     function showClientDetails{}
class Media extends Database{}

我已经创建了一个使用公共方法建立数据库连接的数据库类query($qry)。我从Content课堂开始,现在看起来像这样:


class Content extends Database {
    public function topMenu($page){
        $db = new Database();
        $db->connect();
        $db->query("SELECT m_link, m_title, m_accesskey FROM menu WHERE m_type = 'top'"); 
        $res = $db->getResult();
        foreach($res AS $show){
            if($page == $show['m_link']){
                echo("<li id="active">$show['m_title']."</li>\n");
            }else{
                echo("<li>$show['m_title']."</li>\n");
            }
        }
    }
}

顺便说一句,这有什么意义吗?

在我的 index.php 上,我有以下几行来显示菜单(工作正常)$content = new Content(); $content->topMenu($_aGET[0]);

我失去它的地方是顶部显示客户端列表客户端详细信息的方式,这取决于变量$_aGET[0](包含 url)

假设我想显示客户详细信息,因此我需要来自所有三个表的记录,所以通常我会使用几个连接,就像这样

$query = "
    SELECT cl.c_id, cl.c_client, cl.c_client_desc, ncc.clco_cl_id, ncc.clco_co_id, co.c_content, ncm.clme_me_id, ncm.clme_cl_id, GROUP_CONCAT(me.m_link) AS images_link
    FROM clienten AS cl
    LEFT JOIN norm_cl_co_rel AS ncc ON cl.c_id = ncc.clco_cl_id
    LEFT JOIN content AS co ON ncc.clco_co_id = co.c_id
    LEFT JOIN norm_cl_me_rel AS ncm ON cl.c_id = ncm.clme_cl_id
    LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
    WHERE cl.c_client = '".mysql_real_escape_string($_aGET[1])."'
    AND cl.c_language_id = '"._LANGUAGE."' 
    AND cl.c_active = '1'
";

但就我了解 OOP 的想法而言,我应该为类中定义的每个表都有一个方法(对吗?)但是我将如何加入这些?

还是我的“故事”看起来像:“伙计,放弃它并坚持使用程序编码”?

编辑:

好的,在 Fluffeh 的帖子之后,我使用了他的示例并对其进行了一些修改以进行测试。问题是我确实得到了一些输出,但不是想要的。我的输出如下

编号:公司名称
C
描述:C
媒体:
:
:
:
:
:

虽然我应该得到(值在数据库中):

编号:公司名称
公司名
描述: CompanyName 是一家公司
媒体:
: 图片 1
: 图片 2
: 图 3
: 图片 4
: 图片 5

我的代码如下所示:

class media{
    public $type;
    public $title;
    public $image;
    public $desc;
}

class client{
    public $name;
    public $desc;
}

class clientDetails{

    private $clientID;
    public $clientName;
    public $clientDesc;
    public $clientMedia = array();
    public $clientMediaFiles = 0;

    public function __construct($myID){
        $this->clientID = $myID;
    }

    public function getMyDetails(){

        $db = new Database();
        $db->connect();
        $db->query("
            SELECT c_client, c_client_desc 
            FROM clienten 
            WHERE c_client = '".mysql_real_escape_string($this->clientID)."'
        ");
        foreach($db->getResult() as $client){
            $this->name = $client['c_client'];
            $this->desc = $client['c_client_desc'];
        }

        $db = new Database();
        $db->connect();
        $db->query("
            SELECT ncm.clme_me_id, ncm.clme_cl_id, cl.c_id, me.m_id, me.m_type, me.m_title, me.m_desc, me.m_link
            FROM norm_cl_me_rel AS ncm
            LEFT JOIN clienten AS cl ON cl.c_id = ncm.clme_cl_id
            LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
            WHERE me.m_id IN(1,2,3,4,5)
        ");
        foreach($db->getResult() as $media){
            $this->clientMedia[$i]= new media();
            $this->clientMedia[$i]->type = $media['m_type'];
            $this->clientMedia[$i]->title = $media['m_title'];
            $this->clientMedia[$i]->image = $media['m_image'];
            $this->clientMedia[$i]->desc = $media['m_desc'];
            $this->clientMediaFiles++;
        }
    }

    public function displayMyResults(){
        echo "ID: $this->clientID";
        echo "&lt;div>&lt;h3>".$this->name."&lt;/h3>";
        echo "Desc: ".$this->desc."&lt;br>";
        echo "Media:&lt;br>";
        for($i=0;$i<$this->clientMediaFiles;$i++){
            echo $this->clientMedia[$i]->title." : ".$this->clientMedia[$i]->desc."&lt;br>";
        }
        echo "&lt;/div>";
    }

}
4

4 回答 4

6

继续使用 OOP。一旦你得到它,你就再也不想回到讨厌的、麻烦的、讨厌的、可怕的、狂热的程序代码了。

举个例子:假设我想显示客户详细信息,因此我需要来自所有三个表的记录,所以通常我会使用几个连接,就像这样......

这是一个很好的示例,可用于向您展示 OOP 的有用性。

为ClientDetails创建一个类

  • 在其中创建一个接受 clientID 作为参数的构造函数。
  • 在这个构造函数中,让它运行代码并用查询返回的数据填充它的内部变量。
  • 创建一个函数,将返回的数据输出为良好的格式。
  • 现在从您的主代码创建它并让它显示它的详细信息

突然你在一个类中有几行代码,却可以用 2 行代码完美地展示你的数据。

我将很快添加一些示例代码,看看我是否可以翻阅我的一些课程以进行演示。

编辑:该死,不要翻找旧课程,这太详细了,但我写了一些代码作为示例:

<?php

class clientContact
{
    public $name;
    public $phone;
}

class clientDetails
{
    private $clientID;      //only this class can access this variable.
    public $clientName;     // Anything can change these.
    public $clientPhone;
    public $additionalContacts= array();
    public $associates=0;

    public function __construct($myID)
    // This is a magic function that is called every time we make a new object of this class.
    {
        $this->$clientID=$myID;
    }

    public function getMyDetails()
    // This function will query the database to get it's information properly
    // and populate itself with everything it needs. You could do this as part
    // of the __construct() call, but I didn't want to do TOO much code.
    {
        $sql="select clientName, clientPhone from clients where clientID=".$this->clientID.";";
        // skipping over full SQl bits...
        foreach($stmt as $clientContact)
        {
            $this->clientName=$clientContact->clientName;
            $this->clientPhone=$clientContact->clientPhone;
        }

        $sql="select clientName, clientPhone from associates where assocID=".$this->clientID.";";
        // skipping over full SQl bits...
        foreach($stmt as $clientContact)
        {
            $this->additionalContacts[$i]= new clientContact();
            $this->additionalContacts[$i]->name=$clientContact->name;
            $this->additionalContacts[$i]->phone=$clientContact->phone;
            $this->associates++;
        }

    }

    public function displayMyResults()
    // This function will simply display everything it has in a nicely format
    {
        echo "<div><h3>".$this->clientName."</h3>";
        echo "My contact phone number is :".$this->phone."<br>";
        echo "My associates are:<br>";
        for($i=0;$i<$this-associates;$i++)
        {
            echo $this->additionalContacts[$i]->name." : ".$this->additionalContacts[$i]->phone."<br>";
        }
        echo "</div>";

    }
}

?>

天哪,那是漫长而可怕的,对吧?

并不真地。这就是为什么。

当然,课程中有一些代码,但是现在,您可以在主页上执行以下操作:

<?php 

    $someArray=array(36, 25, 76); 
    // This could be from a query, or a form, or anything else

    for($i=0;$i<count($someArray);$i++)
    {
        $currentContact= new clientDetails($someArray[$i]);
        // This is how we create the object.

        $currentContact->getMyDetails();
        // This now tells the object to get it's own data

        $currentContact->displayMyResults();
        // This now displays the data in the object to the page.
        echo "<hr>";
        unset($currentContact);
    }
?>

使用那一小段代码,您刚刚显示了所有联系人,按照您想要的格式进行了格式化,并且您只是按照您想要的方式完美地显示了所有联系人。

现在想象一下,您将这些对象用于所有内容,而不是像这样的一个小例子。在论坛发帖?一个对象。业务 KPI 的复杂计算?一个对象可以获取它拥有的所有数据,然后计算预测,在图表中显示结果并将其通过电子邮件发送给需要它的用户。

当您来自从上到下执行的 HTML 和 PHP 脚本背景时,OOP 可能会有一个陡峭的学习曲线,但是当您开始掌握它的窍门时,您会希望自己从一开始就学会了它。

编辑:

您的查询中似乎没有该列m_image

    $db = new Database();
    $db->connect();
    $db->query("
        SELECT cl.c_id, ncm.clme_me_id, ncm.clme_cl_id, me.m_type, me.m_title, me.m_desc, me.m_link, m_image
        FROM clienten AS cl
        LEFT JOIN norm_cl_me_rel AS ncm ON cl.c_id = ncm.clme_cl_id
        LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
        WHERE me.m_id IN(1,2,3,4,5)
    ");
    foreach($db->getResult() as $media){
        $this->clientMedia[$i]= new media();
        $this->clientMedia[$i]->type = $media['m_type'];
        $this->clientMedia[$i]->title = $media['m_title'];
        $this->clientMedia[$i]->image = $media['m_image'];
        $this->clientMedia[$i]->desc = $media['m_desc'];
        $this->clientMediaFiles++;
    }

编辑 2:我不是 100% 确定,但可能是返回的字段名称。尝试用这个替换查询:

SELECT cl.c_id as c_id, ncm.clme_me_id as clme_me_id, ncm.clme_cl_id as clme_cl_id, me.m_type as m_type, me.m_title as m_title, me.m_desc as m_desc, me. as m_link
FROM clienten AS cl
LEFT JOIN norm_cl_me_rel AS ncm ON cl.c_id = ncm.clme_cl_id
LEFT JOIN media AS me ON me.m_id = ncm.clme_me_id
WHERE me.m_id IN(1,2,3,4,5)
于 2012-08-01T09:08:13.150 回答
0

当我在 Java 上学习 OOP 时,他们告诉我将每个 Object 类型视为一种新的变量类型。意思是,如果你有一个类Person(PS 好的命名约定是类名中的第一个字母大写),那么持有对象的Person对象可以被认为是 typePerson

我可以给你的最好的例子是当我制作IRC Bot的时候。Bot 需要跟踪Users、Channels 和Servers。IRC 协议完全基于字符串。

虽然我可以使用字符串,但这会大大增加我的应用程序的复杂性以及代码的可读性。相反,我选择将这些数据转换为Channel,UserServer对象,这些对象具有与 IRC 服务器交互的方法。

例如:

/**
 * Add $user to $channel.
 * @param Channel $channel
 * @param User    $user
 *
 * @throws Exception
 */
protected function addUser(Channel $channel, User $user) {
    if (!isset($this->chanList[$channel->name])) {          #Channel is not on channel list
        throw new Exception("You are not on that channel");
    }
    if (!isset($this->userList[$user->nick])) {             #User is not on global user list (New user)
        $this->userList[$user->nick] = $user;               #Add user to list
    }
    $this->chanList[$channel->name]->addUser($user);        #Add the user to the channel user list
}

每当用户加入频道时都会调用它。这允许Bot对象跟踪用户以及他们在哪些频道上。代码进行一些验证,然后将User对象添加到Channel对象中。

现在想象一下,如果你必须只使用字符串,你必须从 IRC 协议中解析每一行,提取所需的数据,并操作一些非常大的数组。最终,你会遇到一大堆混乱,而不是让事情变得井井有条。

于 2012-08-11T09:36:58.573 回答
-1

所以 OOP 是一个很好的方法,例如 MVC 和 Front Controller 模式。但是如果你只想要4页的简单站点,你真的可以使用程序代码,没问题。如果你知道 drupal,那 90% 都是程序代码。

但...

$db = new Database();
        $db->connect();

创建 db 对象并在每种方法中连接并不是一个好主意。更好的是在脚本中只共享一个 db con 对象。你可以使用单例模式并做这样的事情。

class Database extends PDO {

  private static db = null;

  private function __construct() {
        parent::__construct(/* here get some conf data*/);    
  }

  public static getDb() {
    if(!self::db) self::db = new self();
    return self::db;
  }

  /* here you can add your custom methods like loadMenu etc. */
}

更好的是解耦逻辑视图层,请参阅提取 php 函数,它将数组的所有元素添加到实际符号表中(键是该变量的名称,值是值)。使用提取功能,您可以制作漂亮的视图层,将逻辑与视图分离。就像是:

define('TEMPLATE_DIR', __DIR__ . '/templates');

function render($template, $variables) {
  extract($variables);
  require TEMPLATE_DIR . "/$template.tpl.php"; 
}

$variables = array('menu_links' => Database::getDb()->getMenu());

render('menu', $variables);

在你的 menu.tpl.php 中:

<ul>
  <?php foreach($menu_links as $link) : ?>
  <li><a href="<?= $link['href'] ?>"><?= $link['title'] ?></a></li>
  <?php endforeach; ?> 
</ul>
于 2012-08-01T09:21:41.580 回答
-2

PHP OOP 通常归结为一个好的 MVC(模型视图控制器)conecpt 和实现。

如前所述,您通常不需要使用 PHP 进行 OOP,因为它会将核弹射入锡罐而不是棒球……因为网站本身往往是 MVCd,而且冗余代码不会真正伤害那里的任何人(只要因为您在数据库/会话/表单中没有混乱的安全性)

关于 PHP MVC 的一个很好理解的例子是http://anantgarg.com/2009/03/13/write-your-own-php-mvc-framework-part-1/

第一部分非常容易理解,而第二部分(链接在#1 的末尾)有点令人困惑,因为作者重命名了一些类并且没有完全解释它们。

但是查看 zip 文件中提供的代码已经给了你一个好主意。

于 2012-08-01T09:45:39.447 回答