Experimenting with non object oriented PHP code

I'm working on a framework written in PHP and trying to keep the code simple by omitting the functional and object oriented approaches as much as possible. What I'm having in mind might be best defined as loose modular programming. It might lead nowhere good but that's why this is an experiment.


Before I started teaching myself programming from books and videos I had only been familiar with structured programming in the logical sense. Gamedev tools like RPG Maker and the Warcraft III map editor had taught me about variables and the basic control structures (conditional branches, switches and loops). So when I worked on my first dynamic website in PHP I mostly built up on that knowdledge and focused on the stuff that was important to the functionality of the program. Writing my own functions didn't seem very important to me back then (obviously I had not understood the concept of reusing code) and I'm not sure the book I was using for reference even covered classes and objects at all. Years later I came to understand functions better, and managed to somewhat understand OOP a little as well. Yet my first C game was still a mess with dozens of global variables, ridiculously long functions that made use of jumps to navigate back and forth. Eventually I learned to logically divide my code into pseudo modules. For the first time I felt like I'd be able to understand my code if I were to come back to it years later. The natural next step would have been to switch to C++, but when I took a closer look at it none of the features it offered really sold me on it. Starting over and abandoning the plain C code I had written for my game engine didn't seem worth it for what little additional convenience object oriented programming techniques seemed to offer a solo dev. Today I still feel like even pure modular programming is overkill for small projects that can be handled by one or two persons. I like code that is straight to the point and not too abstract. Sometimes it's more elegant to have a couple of globals and to avoid constantly passing variables around. Obviously depending on the nature and size of a project trade offs require to be made however, and that's when evolved modern concepts such as functional and object oriented programming have to come into play. At least that's how it looks to me.
I guess I'm just curious to see how far I can push the lone hacker approach to programming, the one that doesn't have to worry about the next junior dev potentially running a large corporate project into the ground. Honestly I could write an entire post about this topic and might really do so someday.

My first experiments with modular PHP

Let me state for context that I originally started to write this project in OOP style. So I made some decisions early on based on what my code had looked like when it wasn't intended to omit the OOP aspect. As one might expect it didn't turn out very well. I already decided that I'm going to be making major changes to my first draft so I'm posting this here for posterity.

001  class main {
002      use as_module;
004      public function run() {
006          config::init();
007          db::init();
008          store::init();
009          //var_dump(db::uses());
010          request::init();
011      }
013  }

My first consideration had been to figure out how to write PHP code in the way you lay out a modular C program. I thought that classes only holding static methods and properties came pretty close to the concept and thus wrote the trait as_module. Since all my classes so far had been singletons this trait was sort of supposed to be a replacement for my previously written Singleton trait. I chose using a trait in case I'd want to make use of inheritance on my classes later on.

001  trait as_module {
003      static $prop = array();
005      private function __construct() {
006          $trace = debug_backtrace();
007          trigger_error(
008              'Attempting to create object of module class: in '.
009              $trace[0]['file'].' on line '.$trace[0]['line'], E_USER_ERROR);
010      }
012      public static function __callstatic($name, $args) {
013          if (count($args) > 0) {
014              if (strpos($args[0], ':') !== false) {
015                  $a = explode(':', $args[0]);
016                  $a2 = self::$prop[$name];
017                  foreach ($a as $k) {
018                      $a2 = $a2[$k];
019                  }
020                  return $a2;
021              }
022              return self::$prop[$name][$args[0]];
023          }
024          return self::$prop[$name];
025      }
027  }

The property array probably was never necessary. I'm already thinking of replacing it with static properties written straight into the classes. If you can call them that. Can't call them modules either because I plan on having dependencies between each other where needed, just to keep things simple and avoid passing variables around too much. At the very least I don't plan on developing the next facebook with this framework so it should be fine.
It seemed straightforward to lock the constructor away. Do we need objects if we want to avoid writing object oriented code? I didn't think so. Now I'm not so sure anymore. I'll get back to that later.
Lastly I wrote a function to access the property array from outside a class, turning them into namespaced globals using neither namespaces nor globals variables per sē. Admittedly I just really hate the way static properties are accessed in PHP. module::$property just looks plain ugly. Besides a magic function was necessary to at least access the properties since the static array was meant to be private. Thought it can't hurt to prevent unnecessary write access to the variables. Encapsulation is actually a neat feature even for projects that haven't hit corporate scale yet.
Anyways I felt smart using a string parameter to simplify nested array access, so you could access write module::prop('a:b:c'); instead of module::prop()['a']['b']['c'] But it also feels like a waste of processing time (not to mention that part should be offloaded to an array helper) compared to accessing multidimensional array elements directly.
And honestly I don't even know why the property array isn't declared private. I seem to remember it having caused errors, but some quick tests I just did seem to prove that wrong. Anyways...

001  class config {
002      use as_module;
004      // Properties are simply the config array keys
006      public static function init() {
007          self::read_base_config();
008          self::read_db_config();
009      }
011      private static function read_base_config() {
012          $config = array();
013          $config['store'] = array();
014          $config['store']['db'] = array();
015          foreach (new FilesystemIterator(realpath(path::CONFIG)) as $i) {
016              if (is_file($i)) { include($i->getPathName()); }
017          }
018          self::$prop = array_merge(self::$prop, $config);
019      }
021      private function read_db_config() {
022          foreach (new FilesystemIterator(realpath(path::DB_CONFIG)) as $i) {
023              if (is_file($i)) {
024                  $config = array();
025                  $config['connections'] = array();
026                  include ($i->getPathName());
027                  foreach ($config['connections'] as $conn) {
028                      $config['connections'][$conn['key']]['db'] = 
029                          $config['key'];
030                  }
031                  self::$prop['store']['db'][$config['key']] = $config;
032              }
033          }
034      }
038  }

A simple module to load config files and merge them into a monolithic array. Normally you'd use config data to initialize objects. But I felt like copying data out of the config array would be a waste since it was already in memory to begin with. A terrible mistake because I ended up having to bake an additional value into the connection arrays later on, and that's just ugly. Not to mention trying to work with the data without introducing new objects (types) wasn't comfortable and caused me a lot of headaches.

001  class db {
002      use as_module;
004      // Properties
005      // $uses;  The currently used database and connection
006      // $conns; Array of array
007      //
009      public static function init() {
010          self::$prop['conns'] = array();
011      }
013      public static function load($db) {
014          $a = (isset($db['default']) && $db['default']) ? $db['key'] : null;
015          $b = null;
016          foreach ($db['connections'] as $conn) {
017              array_push(self::$prop['conns'], array(
018                  'db' => $db['key'],
019                  'conn' => $conn['key'],
020                  'state' => false
021              ));
022              $b = (isset($conn['default']) && $conn['default']) ? 
023                  $conn['key'] : null;
024              // if ($b) { break; }
025          }
026          self::$prop['uses'] = array($a, $b);
027      }
029      public static function use($db, $conn) {
030          self::$prop['uses'] = array($db, $conn);
031      }
033      public static function checkconn($conn) {
034          foreach (self::$prop['conns'] as $conn2) {
035              if (($conn2['db'] == $conn['db']) &&
036                  ($conn2['conn'] == $conn['key']))
037              {
038                  return $conn2['state'];
039              }
040          }
041          return self::$prop['conns'][$conn['key']];
042      }
044      public static function set_connstate($conn, $bool) {
045          $i = -1;
046          $j = 0;
047          foreach (self::$prop['conns'] as $conn2) {
048              if (($conn2['db'] == $conn['db']) &&
049                  ($conn2['conn'] == $conn['key']))
050              {
051                  self::$prop['conns'][$j]['state'] = $bool;
052                  return true;
053              } else {
054                  $j++;
055              }
056          }
057          return false;
058      }
060  }

So just writing a couple of simple routines for initial database handling turned into a log of pain. This would have taken much less time to write in pure object oriented code. Also I found need to put a flag indicating whether a connection had been set up into each connection array. Putting this piece straight into the config array didn't sit well with me since I meant for the config array data to be immutable, so I tried to keep copies of the little data I needed for the system to work instead. It was really awkward to say the least.


So far this has been a terrible mess that's just hard to read and not nearly as elegant as I had imagined it to be. I'm going to need either real classes or to use creator functions (that return StdClass objects) to mimic C structs. Juggling arrays and strings like that is a pain to work with and awfuly confusing. Maybe forcing type safety might be a good idea too.
The way I'm heading I feel like carefuly writing simple OOP code might be the way to go in general. I'm already looking forward to refactor the pieces of code I have written so far for this project.