2
\$\begingroup\$

I'm new to PHP and I didn't know there is something called coding style standards. Now I'm trying to stick to PSR coding style standards and after reading PSR-4, which is about autoloading standards. I wanted to change my php project to follow the standard. I'm also trying to change my project to be OOP rather than current procedural style.

Now I'm building the project files structure and autoloading strategy. I'm done with it and need your opinion about it, should I go on, or I need to change something?

This is the SF_autoloader.php file that I need your review on. It is in the native habitat (copied from Eclipse and pasted here).

<?php
spl_autoload_register(function ($class) {
    $namespacePrefix = "aap";
    $baseDirectory = __DIR__;
    $fileName = str_replace($namespacePrefix, $baseDirectory, $class);
    require_once $fileName . ".class.php";
});

This is my project files structure:

(C:\xampp\htdocs\)
                 - SF_index.php
                 - SF_contact.php
                 - SF_profile.php
                 - SF_signup.php
                 - SF_signin.php
                 - SF_about.php
                 - adminpanel.php
                 + Applications\
                                +Accounting-system\
                                                   -SF_index.php
                                                   -SF_stock.php
                                                   -...more files.
                                +market-researcher\
                                                   -SF_index.php
                                                   -.....more files.
                 + data \
                         - SF_autoloader.php
                         - Class1.class.php
                         + Acc\
                                Class2.class.php
                         + KsaMarketResearsher\
                                                Class3.class.php

This is my auto loading strategy:

  • I'm going to put every class file in the Data\ folder
  • I'm using aap as the namespacePrefix for everything in this project
  • I'm also going to have 2 subname spaces which are aap\Acc and aap\KsaMarketResearsher

Now all I need to do to autoload is to include SF_autoloader.php/*SF=side effect*/ in every other PHP file, except the class files since the PSR says:

A file SHOULD declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it SHOULD execute logic with side effects, but SHOULD NOT do both.

It also says:

"Side effects" include but are not limited to generating output, explicit use of require or include ...

Examples

  1. \contact.php

    namespace aap;
    require_once "data\\SF_autoloader.php";
    
  2. \Applications\Accounting-system\stock.php

    namespace aap;
    require_once "..\\..\\data\\SF_autoloader.php";
    

So, what do you think about my autoloading PHP file?

\$\endgroup\$
3
\$\begingroup\$

In order of most to least relevant.

1) There are lots of frameworks for PHP websites / apps and you should consider using one. People have written lots of code that you can take advantage of and won't have to write for yourself. Some of it may even be good.

2) I would not store classes in a folder called 'data', because classes aren't data. I'd use 'classes' or 'lib' or 'include' or something else that better conveys what the folder contains.

3) Some commonly used classes (and interfaces) I suspect you may simply want to just include automatically, instead of having the overhead of parsing out where they are from their name with an autoloader. Consider having a second folder for these classes so you can do something like:

<?
foreach (glob('require\*.php') as $file)
    require $file;

for the ones which are used in many places.

4) Having to have 'require_once' at the start of each file is a bit icky - but it depends how big your project is before you worry about fixing it. If you use a framework the problem goes away - do whatever the framework documentation says.

If you want to clean it up with in-house code I would (and there may be other ways?) start by decoupling your request endpoints from the files that respond to the requests with a 'router' file, and have that do the autoloading.

That's perhaps a little vague, so here's an example:

Project structure:

htdocs\
    boot.php
    autoloader.php
    Application\
        index.php
        login.php
        Accounting\
            index.php
            stock.php
    Site\
        index.php
        signin.php
        login.php
        signup.php
        Accounting\
            index.php
            stock.php
    Include\
        something.class.php
        somethingelse.class.php
        Acc\
            another.class.php
    Require\
        exceptions.php
        interfaces.php

Each of the files in 'Site\' looks like this:

<?
define('REQUEST_ENDPOINT', __FILE__);
include '\boot.php';

boot.php looks something like this:

<?
foreach (glob('Require\*.php') as $file)
    require $file;
require 'autoloader.php';

/* anything else you want to do all the time 
   - access control for example */

// do something slightly smarter here
$file = str_replace('\\Site\\', '\\Application\\', REQUEST_ENDPOINT);

include $file;

Files in 'Application\' look however they do at present, less any common code you can combine into the router (or something it includes before including your page).

Fiddle with your apache vhost configs until your requests go to 'htdocs\Site\' instead of 'htdocs\'.

Then when somebody visits 'site.com/Accounting/index.php' they hit 'htdocs\Site\Application\index.php', but that file just marks where the request was to and bounces them down to the router. The router ('boot.php') can then decide what to do with the request and include the correct file to handle it. The user will really be served by the file 'htdocs\Application\Accounting\index.php' (or wherever you choose to send them with logic in the router). But since all your pages go via the logic in 'boot.php' you can centralise things like sessions, error handling and access control instead of having other pages call their own include statements or have to worry about state so much.

One straightforward advantage is that you can alias page names or put similar pages in one file but appear to the user as different places/pages. You can do this with rewrite rules too but this way you can see what pages you have from your folder structure instead of having to open a config file and parse a regex.

As a bonus the user can't possibly navigate to the file 'htdocs\Include\something.php'. The closest they get is 'site.com/Include/something.php' but that would take them to 'htdocs\Site\Include\something.php' which doesn't exist; they get a proper 404 or are redirected to the index instead of getting a white page.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thank you very much for your help. I'm taking every note into serious consideration. I LOVED that router file. from now on I'm going to make every request come to my application into one file. one place to manage everything and initiate everything then it routes the request to it's destination,wow sounds great. and for using framework, I finally started to get use of the php abstraction layer, and I don't want to start learning new abstraction layer from 0 . but sure I'm going to use a framework if it's going to save me time. \$\endgroup\$ – Accountant م Nov 22 '16 at 9:53
  • 1
    \$\begingroup\$ If you have one file that handles every request to your application - a 'front controller', then that file can directly or indirectly include the auto-loader before it includes whatever part of your application is relevant to the request. \$\endgroup\$ – bdsl Nov 22 '16 at 21:01
  • 2
    \$\begingroup\$ @Accountantم don't go crazy with front controller pattern and start routing static assets requests through it. There is no reason PHP needs to come into play for those, and in fact more complex applications typically deliver such assets through a separate CDN or similar geared specifically towards delivering static assets. Also, it is better for server performance to not configure front controller rewrite in .htaccess. Consider doing this in actual .conf file so you don't need overhead of reading htaccess for every incoming request. \$\endgroup\$ – Mike Brant Nov 23 '16 at 4:54
  • 2
    \$\begingroup\$ @Accountantم front controllers are typically at the heart of most modern PHP frameworks, so definitely a pattern you should be familiar with and use as appropriate. \$\endgroup\$ – Mike Brant Nov 24 '16 at 3:45
  • 1
    \$\begingroup\$ @Accountantم re:comment 2 You're welcome :) Having lots of files do their own requires/includes means you're repeating code in lots of places - which means that changing that code (because you rename or move something, or change libraries) can be time-consuming, and it makes unit testing harder. In general you want code that does the same thing in as few places as possible. +1 for not routing all requests for images / css through a boot file / front controller, you don't normally want the overhead unless you're dynamically generating images or something \$\endgroup\$ – ToXik-yogHurt Nov 24 '16 at 6:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.