What are some PHP object-oriented framework initia

2019-06-12 03:41发布

问题:

I have an object oriented framework that uses a page design, where each page extends a view of the framework. So, for instance, my index page for a site is actually a class that implements the abstract class View provided by the framework. I hook the framework by including a startup script at the top of the page and after some processing the framework creates an instance of the page and processes its view data. To add flexibility to the system, I don't require the class name to be the name of the file itself. This allows me to create something like a support class and have it behave as the index for the /support/ subdomain.

I was initially passing the page's class name into the framework via the framework's constructor, but this added a few more steps to the top or bottom of the page. I currently obtain the class name via a pages table in the database identified by a filtered requested URI. I use this table to build navigation and adding an extra table column was practically free. This works OK as long as I have a database connection, but I'm trying to implement static page support for status messages and error reporting, and I need another method for creating an instance of the page's class. If I use the standard convention of naming the class the file's name, then I know I have a dependable way of extrapolating the class name. I don't really want to name all my classes index just for presentation reasons. What is some advice or some standards for how object oriented frameworks are initialized?

View.inc

<?php
abstract class View
{
    abstract function getView();
}
?>

Startup.inc

<?php
    require_once("View.inc");
    require_once("CoreController.inc");

    $Framework = new CoreController();
    $Framework->Initialize();
    exit;
?>

index.php

<?php
    require_once("Startup.inc");

    class Index extends View
    {
        public function getView()
        {
            echo "<pre>View Data</pre>";
        }
    }
?>

Within my framework I have a TemplateController that processes the page. The page class is known because it is mapped via another class. Without a database however, I would like to discover the class within, say, index.php without changing the way it's currently set up. Here is the actual code within the TemplateController.

//Get the View Class from Page
$view = $page->getPageClass();

//We need to catch View creation failure
$this->Page = new $view($this->Framework);

//Initialize the Page View
$this->Page->Initialize();

//Cache the Page View
$this->cacheView($this->Page, $page->getPageName(), $this->SiteID.TCS_PAGE_SORTID);

In the snippet above $view is the actual name of the class that was mapped from another controller. I'm passing a reference to the framework to the view's constructor and the rest is really irrelevant. I'm trying to come up with a similar mapping technique to identify the page class in the event the database is down. I like the one include line for the framework startup and would like to keep it that simple.

At the top of the TemplateController I have to also reinclude the actual page, since my startup script is at the top, the actual class is not included even though it is the requested page.

include($_SERVER['SCRIPT_FILENAME']);

Please review Stack Overflow question Identifying class names from $_SERVER['SCRIPT_FILENAME'] for more information on what I'm attempting to do.

回答1:

Here is my checklist of page routing:

  • Adding new page must be quick
  • You must not be able to add page unintentionally
  • Application with million pages should not be slower or more bloated than application with 2 pages
  • Provide simple way and let people enhance it if they want
  • Allow easy re-factoring, such as moving several pages into different location
  • Make framework detect everything. Don't force user to specify base URL, etc.
  • Create simple to understand page names (hello/world).
  • Clean illegal characters from the URL
  • Make it possible to add static pages easy
  • Provide a way to generate URLs from page names.
  • Allow user to use pretty URLs by changing what appears before and after the page in the URL

And most importantly - Stop copying, think about the best approach.

All of those suggestions I have used in the PHP UI framework - Agile Toolkit where I am a contributor.

Relevant sources: Agile Toolkit - a PHP Framework with jQuery, Agile Toolkit - PageManager.php, Agile Toolkit - URL.php and Agile Toolkit - PathFinder.php.

We wanted to make it really simple for developers. And secure too. And flexible. Therefore the "page" class is selected based on the URL. How? Quite easy:

/hello.html -> page_hello /hello/world.html -> page_hello_world

Class then is mapped into filename. page/hello/world.php

Then there are cases when we want to use dynamic URLs too, such as: /article/234

Many frameworks implement a complex techniques here (arrays, regular expressions, front-controllers). We don't. There is mod_rewrite for this. Just rewrite this into page=article&id=234 and it works. And scales.

Apart from pages, there are other classes, but those classes can't be accessed directly. Therefore pages live under the /page/ folder, do distinguish them and maintain security.

Then comes the designer saying - "I won't write PHP". So we introduce static pages. If class page_hello_world is not defined, we'll look into template/skin/page/hello/world.html. That's a easy shortcut for designers and non-developers to add a new page.

What if a page is not found? Api->pageNotFound() is called. Feel free to redefine and load pages from SQL or display 404 page with a picture of a pink elephant.

And then there are some pages which come from add-ons. We don't want to enable them by default, but instead let users add them to their app somewhere. How?

class page_hello_world extends Page_MegaPage

Next question, is how we handle sub-pages of that page, since sometimes all the functionality can't fit on single page. Well, let's add support for page_edit() method (or any page_XX) as an alias for a sub-page inside those classes. Now add-on developer can include a multifunctional page which can be extended, customized and placed anywhere in the application.

Finally there are hackers, who want to do something really fast. For them we apply same technique to the API. You can define function page_hello_world in the API, and you don't need class.

Some might say that there are too many ways to do a simple thing. Oh well.

I hope that this was helpful.



回答2:

Use __autoload(). Most major PHP frameworks use autoloading to streamline class loading.



回答3:

You need some way to map a URL to an object, which is usually handled by a routing component in most frameworks. Might want to take a look at libraries such as https://github.com/chriso/klein.php, or the routing components of the major Frameworks out there (Zend, Symfony, etc.).



回答4:

Why not to use information from URL to detect correct class? Since you won't use database for static pages, you have to somehow store mapping between URL and class in file. I.e. you will have a file mapping.php:

return array(
  'about' => 'AboutView',
  'copyright' => 'CopyrightView',
);

Here, about and copyright are URL components and values represent appropriate child classes of View. You can have URL's like http://example.com/index.php?page=about and use rewriting capabilities of webserver to make them look good.

You will change implementation of Page::getPageClass() in order to return correct view class. Depending on URL it will use static mappings from the file above or use database.

What's the problem with this approach?