Jump to content

Core Libraries


Recommended Posts

I am making a project (which I would like to distribute), and I want to load core libraries into main class.

 

Example Main Class:

class Main{
    public function loadCore(){
        // Load core libraries
    }
}
$_main = new Main();
$_main->loadCore();

 

Once loadCore is run, I would like to load all the files in /root/core/net and /root/core/xml (which I have already done).

Next I want to make them easily accessible, but I am not sure of an easy way to access them. I want to make it easy for beginner programmers (and advanced programmers).

 

maybe so they have to do something like this:

 

require_once 'root/Main.php'; // Automatically creates an instance
$_main->http->someFunction();
// or
$_main->net->http->someFunction();
// or
$_main->someFunction();

 

The example structure:

+- root
|    +- core
|    |    +- net
|    |    |    +- Http.php
|    |    |    +- Other.php
|    |    |    +- Other2.php
|    |    +- xml
|    |    |    +- Xml.php
|    |    |    +- Other.php
|    |    |    +- Other2.php
|    +- plugins
+- Main.php

 

Basically I am just looking for some input on how I could make this SUPER easy to use. The less work the programmer has to do the better. Any thoughts?

Link to comment
Share on other sites

class Main{
    public function __call(){
        // Call the function
    }
}

class A{
    public function somthing(){
        // Do some stuff
    }
}

class B{
    public function somthing(){
        // Do some stuff
    }
}

$mc = new Main();
$mc->something();

 

Which one does it call?

Link to comment
Share on other sites

Here's a real quick example of what I'm talking about. Real quick. If I were doing it seriously then it would be a little different.

class Main {

private $_tree = array(
	"net" => array(
		"http" => 'root/core/net/Http.php$Net_HttpClass',
		"other" => 'root/core/net/Other.php$Net_OtherClass'
	),
	"xml" => array(
		"xml" => 'root/core/xml/Xml.php$Xml_XmlClass',
		"other" => 'root/core/xml/Other.php$Xml_OtherClass'
	)
);
private $_traversal = null;

public function __get($name) {
	if ($this->_traversal == null) $this->_traversal = new MainTraversal($this->_tree);
	return $this->_traversal->$name;
}

}

class MainTraversal {

private $_tree = array();

public function __construct(array $tree) {
	$this->_tree = $tree;
}

public function __get($name) {
	if (isset($this->_tree[$name])) {
		if (is_string($this->_tree[$name])) {
			list($file, $class) = explode('$', $this->_tree[$name]);
			if (!class_exists($class)) require_once($file);
			return new $class();
		} else {
			return new MainTraversal($this->_tree[$name]);
		}
	} else {
		return null;
	}
}

}

If you want that serious version I'll do it for you, by the way. I like this kind of stuff.

Link to comment
Share on other sites

@requinix I will give your code a try when I get time later today.

 

Currently this is what I have to load main items for this library:

	public function loadCore(){
	foreach(glob($this->location."/core/*/*") as $coreFile){
		$info = (object)pathinfo($coreFile);
		require_once $coreFile;
		$pos = strrpos($info->dirname, "/");
		$coreMedia = substr($info->dirname, $pos + 1);
		$this->loadedFiles['core'][$coreMedia]['path'][] = $coreFile;
		$this->loadedFiles['core'][$coreMedia]['files'][] = $info->basename;
	}
}

At the moment it doesn't create instances or linking of any kind to make it so the methods in the class are usable.

 

@gizmola I am not sure if that is what I am looking for... I use it, but I am not sure if I want it for this issue.

Link to comment
Share on other sites

Typically the reason you're loading this core stuff in is because it is going to be used.  In terms of structuring code, the autoloader implementation often depends on a class name convention. 

 

You have code that could be handled by the autoloader, which is not only pointless, but a bad idea in most cases, because you don't want to load code that you're never going to use.  So the main thing I see missing is that this core code should be used to create some objects that become part of your api.  The naming of these objects as well as their visibility is a lot more important than the mechanics of how they got loaded.

Link to comment
Share on other sites

I don't want members that use this to have to do this:

 

$inst = new MyClass();

 

Mainly for Ease of use.

 

With my plugins, all I do is this:

 

$plugins = "Mysql,Twitter";
require_once "dir/Main.php";

 

This will then ONLY load the Mysql and Twitter plugins, and none of the other ones.

 

or, I can do:

$disablePlugins = true;
require_once "dir/Main.php";

 

Which will then not load any of the plugins.

Link to comment
Share on other sites

With all due respect to your users, you have to let go of their hands at some point. If they're mucking around with PHP code then there's nothing wrong with expecting them to know how to muck around with PHP.

 

You're talking about members... Who are these people? What are they doing with your code?

Link to comment
Share on other sites

Okay. But still: who's the target demographic? If they have any (or should be expected to have any) PHP experience then introducing complex syntaxes for simple tasks will only mean they have to learn more stuff just to use your code.

Link to comment
Share on other sites

To be specific, I'm talking about the difference between

$_main->foo->bar->drawCalendar();
// and
$foobar = new Foo_Bar();
$foobar->drawCalendar();

As a PHP developer I prefer the second version because I know what's going on. It's simple. It's stuff I've done before. The first version is doing some kind of trickery to get, well, something, and I won't know what it is unless I look through your code or manual or documentation.

But to someone with... less than sufficient programming experience, the first is easier for them to learn.

 

Which is why I'm wondering about your audience.

Link to comment
Share on other sites

You can't serve the entire market (from beginner to advanced). Advanced users for example require functionality that reaches far beyond what beginners will ever need (ORM, DBAL, SOAP Client/Server, ..). Advanced users will also most likely use an IDE with type hinting of which it can't benefit if a large portion of your code is hidden behind magic methods like __call(), __set() and __get(). Both Symfony as CodeIgniter (Zend for it's action and view helpers) use this approach which I find annoying since I don't get a nice listing of available methods/properties.

Link to comment
Share on other sites

OK, based off what you said with IDE hinting, here is how I load plugins, it works, but in my IDE it doesn't do hinting. It creates the instance in the foreach loop. What do you think of this method of loading?

 

public function loadPlugins($loadPlugins = null){
if(is_string($loadPlugins)){
	$loadPlugins = explode(",", $loadPlugins);
}
$ini = $this->allpluginSettings();
if($loadPlugins == null){
	foreach($ini as $sectionClass => $section){
		require_once $this->location."/plugins/".$section['root']."/".$section['fileName'];
		$this->$section['instanceName'] = new $sectionClass();
		$this->loadedFiles['plugins'][$section['root']]['path'][] = $this->location."/plugins/".$section['root']."/".$section['fileName'];
		$this->loadedFiles['plugins'][$section['root']]['files'][] = $section['fileName'];
	}
}
}

 

I then can call the class like this:

$myClass->example->someMethod();

 

Example INI file:

[ExampleClass]
root = Example
fileName = ExampleClass.inc.php
instanceName = example
sessionRef = exmple

[Mysql]
root = Mysql
fileName = Mysql.inc.php
instanceName = mysql
sessionRef = mysql

Link to comment
Share on other sites

public function loadPlugins($loadPlugins = null){
if(is_string($loadPlugins)){
	$loadPlugins = explode(",", $loadPlugins);
}
$ini = $this->allpluginSettings();
if($loadPlugins == null){
	foreach($ini as $sectionClass => $section){
		require_once $this->location."/plugins/".$section['root']."/".$section['fileName'];
		$this->$section['instanceName'] = new $sectionClass();
		$this->loadedFiles['plugins'][$section['root']]['path'][] = $this->location."/plugins/".$section['root']."/".$section['fileName'];
		$this->loadedFiles['plugins'][$section['root']]['files'][] = $section['fileName'];
	}
}
}

 

This code, while an initial draft, isn't reusable nor properly tested:

 

1. You assume that any passed string is CSV

2. Once $loadPlugins != NULL you don't use it anywhere besides explode() it when it's a string which in turn isn't used anywhere.

3. $this->allpluginSettings() is called while the returned value is only used when $loadPlugins == NULL

4. Files are loaded through the require_once mechanism instead of a generic loader class

5. It's assumed the require_once will ALWAYS point to a file, and it will ALWAYS contain a class, so that $this->$section['instanceName'] = new $sectionClass(); never fails.

6. Exceptions/Error's aren't caught.

7. Using deep nesting $this->loadedFiles['plugins'][$section['root']]['files'] instead of using an object to represent the data structure.

 

$myClass->example->someMethod(); still has the problem of no type-hinting unless you specify phpDoc @property comments on the class but since you are aiming for a plugin architecture this is not an option.

 

No type-hinting is not only an IDE problem, it will also be hard for beginners to actually be able to understand why tutorials tell them stuff like:

 

$o = new SomeObject(); while your framework loads it on-the-fly under a different name. If you want to teach beginners something, teach them how to program OO properly instead of showing them magic tricks.

 

MyCoolFramework::create('User')->username('ignace')->password('foobarbaz')->authenticateSession()->setProfileAvatar(new Avatar('bar.png'))->save();

 

May look cool, but programming isn't about creating giant one-liners.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.