Jump to content

OOP - Namespace, spl_autoload_register, PSR-4


benanamen

Recommended Posts

So now I have some classes that need to be used by the application. From what I can gather, now I need to know several things to "include" them in the app such as Namespaces, spl_autoload_register, and PSR-4.

 

Could someone please put these things in perspective and when/how to implement. I have read up on each of these items. I am not grasping it as of now.

 

It also seems to be that their is a particular directory structure for the class files and not just a single directory with all the class files in it.

Link to comment
Share on other sites

- I could write out an explanation of namespaces, but it would be easier to just point you to the documentation. Namespaces are optional but more "professional" than continuing to name classes with underscores.

- spl_autoload_register is about autoloading. It means you don't have to do a require_once for every single class file you need. If you're familiar with __autoload, spl_autoload_register is a better alternative.

- PSR-4 is a recommendation about how to use namespaces. It's pretty basic, one of the least controversial PSRs, and almost universally accepted.

 

<?php // root/code/MyWebsite/Core/User.php

namespace MyWebsite\Core;

use MyWebsite\Model;

class User {

	public static function get($username) {
		$user = Model\User::get($username); // MyWebsite\Model\User
		return $user ? new self($user) : null;
	}

}

?>

<?php // root/code/MyWebsite/Model/User.php

namespace MyWebsite\Model;

use MyWebsite\Db;
use MyWebsite\ModelBase;

class User extends ModelBase {

	public static function get($username) {
		$db = new Db(); // MyWebsite\Db
		$row = $db->get("users", "username", $username);
		return $row ? new self($row) : null;
	}

}

?>


<?php // root/bootstrap.php

// this autoloader only applies to MyWebsite\* classes
spl_autoload_register(function($class) {
	if (strncmp($class, "MyWebsite\\", 10) == 0) {
		$file = __DIR__ . strtr($class, "\\", DIRECTORY_SEPARATOR) . ".php";
		is_file($file) && require_once($file);
	}
});

?>

<?php // root/public/login.do.php

require_once("/path/to/root/bootstrap.php");

$user = MyWebsite\Core\User::get($_POST["username"]);
if ($user->login($_POST["password"])) {
	header("Location: /");
} else {
	header("Location: /login?invalid");
}

?>
Can you ask more specific questions than just "please explain everything"?
  • Like 1
Link to comment
Share on other sites

RE: spl_autoload_register

 

I am using the example code from the manual and it works.

spl_autoload_register(function ($class) {
    include 'classes/' . $class . '.class.php';
});


$valid_login = new LoginAttemptsLog($pdo);
$valid_login->logSuccessfulAttempt('new_goodusername');

Through testing I see that it somehow reads new LoginAttemptsLog into $class and thinks it is a filename to look for in the classes directory. Do I need to understand anything more than this? What else is there to know about this?

Link to comment
Share on other sites

When PHP encounters a class that hasn't been loaded, it triggers autoloaders. If you called spl_autoload_register then all of those will be called in order until one of them causes the class to be defined (like through an include/require).

 

Since your autoloader indiscriminately tries to include "classes/*.class.php", and $class is set to "LoginAttemptsLog", then it will try to include "classes/LoginAttemptsLog.class.php" using the normal rules for including a file with a relative path.

If you tried to instantiate a "Site\LoginAttemptsLog" then the code would try to include "classes/Site\LoginAttemptsLog.class.php".

 

What else is there to know... about the code you posted? About autoloading in general? PSR-4? Namespaces?

Link to comment
Share on other sites

Since your autoloader indiscriminately tries to include "classes/*.class.php",

 

Is the manual example a bad usage?

 

What else is there to know... about the code you posted? About autoloading in general? PSR-4? Namespaces? 

 

Question was regarding the autoloader. I want to know it inside and out before I go on the the next item.

Edited by benanamen
Link to comment
Share on other sites

In my experience, using namespaces requires a bit more work than that in the autoloader. For instance, to use requinix's example of "Site\LoginAttemptsLog" converting to "classes/Site\LoginAttemptsLog.class.php", that's not going to be a valid path due to the backslash. So you'd want to explode the class string on a backslash, then implode the resulting array using the directory separator as the glue. This'll give you an include path like "classes/Site/LoginAttemptsLog.class.php", which of course you'll want to test to make sure exists and is a readable file, plus other security checks and stops that Jacques1 can explain far better than I. As long as you follow the directory structure conventions, you should be golden. It's like the days of PEAR naming conventions where file names were long and words separated by underscores, except now the underscores are backslashes and you've got the ability to use the 'use' directive in your code to cut down on the amount of typing you have to do.

Link to comment
Share on other sites

Is the manual example a bad usage?

It's fine for smaller projects, but like maxxd said it should do things like fix backslashes and test that the file exists.

 

So you'd want to explode the class string on a backslash, then implode the resulting array using the directory separator as the glue.

strtr() is much simpler.

$fixed_class_path = strtr($class, "\\", DIRECTORY_SEPARATOR);

plus other security checks and stops that Jacques1 can explain far better than I.

I'm not going to argue with him if he comes in and says something, but "security checks" implies someone is able to craft an arbitrary class name and cause your code to execute it, and possibly also got an unauthorized file onto the server. But I'm not even sure it's possible to trigger autoloading on an invalid class in the first place.

spl_autoload_register(function($class) { var_dump($class); });

$c = "!@#$%^&*()\\Abc";

class_exists($c); // no output
new $c(); // no output
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.