doucheng7234 2014-03-17 11:28
浏览 45
已采纳

PHP构造对象数组

As a means to try and learn object oriented PHP scripting, I'm currently attempting to rewrite a database web application that I previously wrote in procedural PHP. The application is used to store car parts and information about car parts.

In my application there are car parts. They are identified by various reference numbers, which are assigned by different organisations (the part's manufacturer, re-manufacturers, vehicle manufacturers, etc.), and any particular car part could have zero, one or many reference numbers as assigned by these organisations (and, confusingly, each reference number may refer to more than one unique car part as defined in the database I'm working on).

As far as I understand things, I am dealing with three different classes of entities. There is that of the car part, the reference number, and that of the reference-assigner (in my internal nomenclature I call these 'referrers'). As I am just getting started with learning OOP, I have begun by creating some very basic classes for each:

class Part {
    public $part_id;
    public $part_type;
    public $weight;
    public $notes;

    public $references;

            private $db;

            function __construct(Database $db) {
                $this->db = $db;
            }

}

class Reference {
    public $reference_id;
    public $reference;
    public $referrer;
            private $db;

            function __construct(Database $db) {
                $this->db = $db;
            }
}

class Referrer {
    public $referrer_id;
    public $referrer_name;
            private $db;

            function __construct(Database $db) {
                $this->db = $db;
            }
}
?>

What I've been struggling with is how to populate these and subsequently glue them together. The most basic function of my web application is to view a car part, including its metrics and its assigned reference numbers.

A part_id is included in a page request. Initially, I wrote a constructor method in my Part class which would look up that part in the database, and then another method which would look up reference numbers (which were JOINed with the referrer table) assigned to that Part ID. It would iterate through the results and create a new object for each reference, and hold the complete set in an array indexed by the reference_id datum.

After further reading, I began to understand that I should use a factory class to carry this out, however, as this kind of conjunction between my Part class and my Reference class is not the responsibility of any one of those discrete classes. This made conceptual sense, and so I have since devised a class that I've called PartReferenceFactory, which I understand should be responsible for assembling any kind of collation of part reference numbers:

class PartReferenceFactory {

    public static function getReferences(Database $db, $part_id) {


    $db_result = $db->query(
        'SELECT *
        FROM `' . REFERRER_TABLE . '`
            LEFT JOIN `' . REFERENCE_TABLE . '` USING (`referrer_id`)
            INNER JOIN `' . REFERENCE_REL . '` USING (`reference_id`)
        WHERE `part_id` = :part_id
        ORDER BY `order` ASC, `referrer_name` ASC, `reference` ASC',
        array(':part_id' => $part_id);
    );

    if(empty($db_result)) {
        return FALSE;
    } else {
        $references = array();

        foreach($db_result as $reference_id => $reference_properties) {

            $references[$reference_id] = new Reference($db);
            $references[$reference_id]->reference = $reference_properties['reference'];
            $references[$reference_id]->referrer = new Referrer($db);
            $references[$reference_id]->referrer->referrer_id = $reference_properties['referrer_id'];
            $references[$reference_id]->referrer->referrer_name = $reference_properties['referrer_id'];
        }
        return $references;
    }
}

}

    ?>

The getReferences method of my factory class is then called inside my Part class, which I revised thusly: class Part { public $part_id; public $part_type; public $weight; public $notes;

    public $references;

    private $db;

    function __construct(Database $db) {
        $this->db = $db;
    }

    function getReferences() {
        $this->references = PartReferenceFactory::getReferences($this->db, $this->part_id);
    }

}

Really I'm looking for advice on whether my general approach is a good one or if, as I suspect, I've misunderstood something, am overlooking other things, and am tying myself in knots. I will try to distill this into some underlying, directly-answerable questions:

  1. Does my understanding of the purpose of classes and of factory classes seem erroneous?

  2. Is it a bad idea for me to store arrays of objects? I ask from a viewpoint more of design than performance, insofar as they are not intertwined.

  3. Is this even an appropriate way to structure relationships/inter-dependencies between classes in PHP?

  4. Is it correct to call my PartReferenceFactory inside the getReferences method of the (instantiated) Part class? And is storing the returned reference objects within the part objects appropriate?

  5. As a part of the application's GUI, I'll need to provide lists of referrers, requiring me to create another array of ALL referrers independently of any part object. Yet some of these referrers will exist within the $references array inside the part object. It has occurred to me that in order to avoid duplicate referrer objects, I could SELECT a list of all referrers at the beginning of each page request, formulate these into a global array of referrers, and simply reference these from within my Part and Reference classes as needed. However, I have read that it is not good to rely on the global scope within classes. Is there an elegant/best-practice solution to this?

Thank you very much for the time of whomever happens to read this, and I apologise for the extremely long question. I often worry that I mis-explain matters, and so wanted to be as precise as possible. Please let me know if it would be beneficial for any parts of my post to be deleted.

  • 写回答

1条回答 默认 最新

  • douzi1991 2014-03-17 18:05
    关注

    Hmmm, I think Jon is right, this question has taken real commitment to get my head round and I'm still not sure I know everything you're asking, but I'll give it a go.

    1) Is your understanding of classes/factory classes right? Well yes and no. Yes you do understand it, but you're taking a very classroom type approach to the problem, rather than the sort of pragmatism that comes with experience. OOP is a way of modelling real things, but it's still fundamentally a programming tool, so don't over complicate your structure, just to keep it real. The main think OOP gives you over structured programming is inheritance, which means you can code things which are kind of like other things, so reuse code better by only coding the stuff that's actually different. If 2 things would share code, make them a shared parent and put the code in there. Envisaging how the hierarchy might work efficiently is 80% of the task of designing an OOP application, and you're bound to get it wrong first time and have to restructure. For example. I've coded a number of classes which represent entities in a database: ie Users, Realthings, Collectibles. Each has fundamentally different set of attributes and relations, but also has a core set of things that are similar: the way they're interrogated, the way the data is presented, the fact that they have attributes, fields and relations. So I coded a parent class which everything inherits, and it contains most of the code, then the specific children just define the stuff which is different for each class, and the hard work was deciding how much could go in Indexed to avoid repeating code in the child classes. Initially I had a lot of code in the children, but as it evolved I moved more and more code into the parent class, and thinned out the children. Like I say, don't assume you'll get it right first time.

    2) Is it a bad idea to store objects in arrays? Well no, but why would you want to? In your example you have an array of references in the database, where the relationship is a many to many relation (ie you have 3 tables with a joining table in the middle). Then when you get the data you create each object and store it in an array. Sure you can do that, but remember each object has an overhead. Loading everything into memory is fine, but don't do it unless you need to. Also be sure you need a many<=>many relationship. I may have mis-read your explanation, but I thought you'd only need a one<=>many relationship, which could be done by storing a reference to the 'one' in the record of each of the 'many' (thus loosing the middle table and simplifying the join).

    5) I'm going to jump to the last one at this point because it feeds into #2. You need to think of your application from different perspectives (a) when you have data and are trying to present it (read) (b) when you have some data and are trying to add new data, with links to existing data (adding a relation) and (c) when you have no data, and are adding a fresh record. How might the user get to each of those perspectives and what would happen. It's often easy to get (a) and (c) to work, but making (b) intuitive is often the hard part, and if you over complicate it, then users simply won't get it. When building up the inner data structures in #2 only do what you need, for the perspective a user is in. Unless you're writing an app, you don't need to load everything, only the stuff for the task at hand.

    3) Not sure what you mean by 'is this appropriate'. OOP allows you to tie yourself up in knots, or create wonderful works of art. In theory you should just try to keep it simple. There are great books which give examples of why you might want to make things more complicated, but most of the reasons aren't obvious, so you'll need experience to decide if what you're doing is needlessly over complicating things or if it actually avoids a pitfall. From personal experience if you think it's overcomplicating, it probably is.

    4) Not sure if this is what you meant, but I've taken this question to be asking if you've used Factory classes correctly. My understanding of the theory is that what you should end up with, is next to no references to doing things statically, beyond the initial creation of a FactoryClass object, stored statically in the child class being used, then you have to code an abstract method in parent class, implemented in each child class, which gets you that object, so you can call on the object of that FactoryClass, using a method call. I normally only call FactoryClass stuff directly when a non-factory class is initialised (ie you need to populate the static in a new object, incase the class hasn't been init'd yet). I don't see any problem calling it directly as you have, but I'd avoid that as the Factory is IMHO an implementation detail of the class, and so shouldn't be exposed outside that.

    In my experience you're always learning new things and discovering pitfalls in OOP, so even thought I've been coding professionally for nearly 20 years, I'd not claim to be an expert on this, so I'm sure there will be totally opposing views to what I've said. I think you learn most by doing what your gut says is right, then not being too stubborn to start over again, if you gut changes it's mind :-)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度