Smarty_Internal_TemplateCompilerBase not found - php

composer.json:
{
"require": {
"smarty/smarty": "v3.1.17"
}
}
index.php:
define('SMARTY_SPL_AUTOLOAD', 1); // now smarty should use its own autoloader
require_once __DIR__ . "/vendor/autoload.php";
function my_classes_loader($class) {
$path = "{$class}.class.php";
if (file_exists($path)) {
include_once $path;
return true;
}
return false;
}
spl_autoload_register('my_classes_loader');
$smarty = new Smarty();
$smarty->setCompileDir("templates_c");
$smarty->display('main.html');
exit();
If I open it in browser I get
Fatal error: Class 'Smarty_Internal_TemplateCompilerBase' not found in
//smarty-example/vendor/smarty/smarty/distribution/libs/sysplugins/smarty_internal_smartytemplatecompiler.php
on line XX
The file is there. And it has content. And it is accessible / readable for PHP etc.
What am I doing wrong? What is missing?

It is a good idea to only have one point deciding about autoloading, and this should be Composer alone.
Try to put your own autoload function away, use a autoload declaration in your composer.json instead. Unfortunately you are not using either PSR-0 or PSR-4 naming standard, but Composer allows you to use "classmap" in this case. Consider moving all your file names to comply with PSR-0.
And the smarty autoloading should already be done by requiring it via Composer. No need to set that constant.
Last but not least I think your autoload function should not return anything. Especially it should not return false if it cannot find the file it supposes to contain the class, because depending on how the autoload functions are ordered on the stack, your function might get called first for ALL classes, including all Smarty ones. If you return false in these cases, you destroy the working autoload stack by not allowing later functions to load that class.
So all in all it is best to use Composer for all autoloading. The developers did everything to provide the best performing autoload function - your own function probably can only be as fast as theirs, but will probably be slower.

Related

Can php spl_autoload_register & composer autoloader work together?

After a little bit of research and have been unable to locate a solution to my problem. I am utilizing an API that is namespaces that I downloaded via composer. The API has it dependences that I allow composer to manage and autoload for me. Separate from this I have about 10 classes that I have autoloaded with utilizing php's spl_autoload_register. Recently, I started mixing the classes to finish up part a project and the whole thing has gone to crap. My custom classes cannot use the composer classes and visa versa. Is there a method I can use to autoload classes that are in two separate folders and that are loaded with two separate outloader.
Here is the code that I currently use. The vender/autoload.php is no different then your typical composer autoloader. Thanks for any assistance.
require 'vendor/autoload.php';
require 'functions/general.php';
require 'include/mailgun.php';
function my_autoloader($class) {
require 'classes/' . $class . '.php';
}
spl_autoload_register('my_autoloader');
Well, actually composer utilizes spl_autoload_register, so answer is 'yes', they can. The autoloading mechanism is supported by autoloader stack - basically, if class didn't appear in runtime after one autoloader has been run, next one is used, until stack runs out of autoloaders and PHP reports an error about a class it can't find. Every spl_autoload_register call basically adds new autoloader, so there may be plenty of autoloaders in memory. The main point of this story is autoloader that can't load class does nothing, the autoloading block of code simply ends with no action taken so next autoloader may take responsibility of class loading. The only thing you need to implement is check in your autoloader that it can handle current class loading (checking that file exists before requiring it is enough, though you should think about possible directory nesting in case of namespaces), and everything should work smooth in future:
function my_autoloader($class) {
$path = sprintf('classes/%s.php', $class);
if (file_exists($path)) {
require 'classes/' . $class . '.php';
}
}
After further research due to ideas that the both #Etki and #Sarah Wilson gave me I came up with the following solution. Thank You both for your input.
require 'vendor/autoload.php';
require 'functions/general.php';
require 'include/mailgun.php';
function autoLoader ($class) {
if (file_exists(__DIR__.'/classes/'.$class.'.php')) {
require __DIR__.'/classes/'.$class.'.php';
}
}
spl_autoload_register('autoLoader');
Hint: I added the __DIR__ to the beginning of the file paths inside the autoLoader function.
If this is for a small project where you are including files from two or three folders you can use a simple if statement.
function my_autoloader($class) {
if(file_exists('functions/'.$class.'.php')){
require 'functions/'$class.'.php';
} else if(file_exists('vendor/'.$class.'.php')){
require 'vendor/'.$class.'.php';
} //add more as needed
}
spl_autoload_register('my_autoloader');
For larger applications, I recommend naming your classes files and your classes for what they are or do, and have them in a specific folder by their names Example: controllers/userController.php for userController class functions/generalFunctions.php generalFunctions class then you can check the names and if it has controller then you include it from the controllers folders. Create an array within the my_autoloader function or in a separate file like.
loadMap.php
return [
'controller' => 'path/to/controllers/',
'function' => 'path/to/functions/',
'helper' => 'path/to/helpers',
'etc' => 'path/to/etc/'
]
filewithautoloadfunction.php
function my_autoloader($class){
$loadMap = require 'path/to/loadMap.php';
foreach($loadMap as $key => $path){
if(stripos($key, $class){
require_once $path.$class.'.php';
}
}
}
spl_autoload_register('my_autoloader');

avoid redeclaring an interface for more one time

I have an interface which I named Manager, and two classes UtilisateurManager and StageManager, and the both of them implements the Manager interface.
In each class I included the interface Manager as the following :
require '../helpers/Manager.class.php';
Then I needed to use these two classes at once in a php script, but I got the error that I can't redeclare class Manager.
I tried to work with the function class_exists() but it's not useful in my case.
How can I solve this problem ?
Maybe you can use require_once instead of require.
require_once '../helpers/Manager.class.php';
You need to implement a simple autoloader which will try to load class/interface only if it isn't already loaded, and forget about direct require/include then. It is considered good practice to leave the filesystem details out of the class file: you may reuse it in other project where your directories system might change, so you'll need to edit the class again.
A simple example:
class Autoloader
{
protected $directories = array();
public function register()
{
// register 'loadClass' method as an autoloader
spl_autoload_register(array($this, 'loadClass'));
}
public function addSource($dir)
{
$this->directories[] = $dir;
}
public function loadClass($className)
{
foreach ($this->directories as $dir) { // search in every registered sources root
$fileName = $dir.DIRECTORY_SEPARATOR.$className.'.class.php';
if (file_exists($fileName) {
include($fileName);
return; // halt when file was found
}
}
}
}
// bootstrap file
$autoloader = new Autoloader;
$autoloader->register();
(spl_autoload_register documentation)
Please note that this realization will cycle through the folders, and this is certainly not the desired solution. The best option today is to build project according to PSR-4 spec - autoloader implementation will have to check existence of a single file only. It may be a little hard to dive into namespaces without any preparation, but once you get familiar with this coding style, you will forget about direct file load.
The last thing, i want to warn you about your naming convention - your Interface is stored in a .class.php file, and this is confusing.

spl_autoload_register is not initializing autoload stack

I am trying to use the SwiftMailer php library with a program that I wrote. I have been using the spl_autoload_register() function just fine before including this library. However, prior to using this library I was explicitly defining the class extensions and locations using the spl functions:
set_include_path(get_include_path().[my include path]);
spl_autoload_extensions('.class.php');
spl_autoload_register();
session_start();
The problem I'm running into, is that now I'm trying to use a library that does not follow along the same naming conventions. Their own autoload class (built by the initial call to the library) looks like this.
public static function autoload($class)
{
//Don't interfere with other autoloaders
if (0 !== strpos($class, 'Swift_'))
{
return;
}
$path = dirname(__FILE__).'/'.str_replace('_', '/', $class).'.php';
if (!file_exists($path))
{
return;
}
if (self::$initPath && !self::$initialized)
{
self::$initialized = true;
require self::$initPath;
}
require $path;
}
When I try to simply run the program after calling their class I get:
Fatal error: spl_autoload() [<a href='function.spl-autoload'>
function.spl-autoload</a>]:Class Swift_MailTransport could not
be loaded in [my file] on line 30
Line 30:
$transport = Swift_MailTransport::newInstance();
I have tried using a custom autoload class modeled after theirs, however, all I get when I try:
var_dump(spl_autoload_functions());
results:
bool(false);
I know this has to be a fairly simple issue, something that I'm overlooking, but I can't find it.
Any help would be greatly appreciated.
Try removing this:
spl_autoload_register();
From the documentation:
[if] spl_autoload_register() is called without any parameters then
[spl_autoload(...)] functions will be used
Knowing that, it's only logical to think that spl_autoload does not know where to load your SwiftMailer classes because the errors you get say so. It then follows that SwiftMailer is not in your include path because spl_autoload tries to load from there.
Next step is to put your SwiftMailer classes in one of the include paths.
Ok, after knocking my head against the wall all day and getting nowhere, I got a great piece of feedback from my brother who is also a programmer.
The whole problem, stemmed from this one line:
require_once(SITE_ROOT.'/classes/lib/swift_required.php');
The SITE_ROOT variable was actually referencing the web location (i.e. http://), with my current host, this does not work, it needs to use the physical file location instead. After making this change, the included autoloader works as advertised.

Most efficient way to load classes in PHP

I'm a c# developer, so I'm used to simply compiling a library and including it within a project for use. I haven't really figured out the best way to load different objects within a PHP application. I don't want to keep using require. What is a good approach to take?
If you're using PHP 5.x, you probably want autoloading.
You don't need to keep using require. You can require_once() which will only parse the file if it has not already been loaded.
Also in PHP, since the includes happen at runtime you are free to require_once() in the middle of a conditional if it is appropriate.
// Only load Class.php if we really need it.
if ($somecondition) {
// we'll be needing Class.php
require_once("Class.php");
$c = new Class();
}
else // we absolutely won't need Class.php
I was C# developer in the past and I can tell you that you need to think bit different if you want to write PHP sites. You need to keep in mind that every unnecessary include will increase extra expenses of resources, and your script will work slower. So think twice before add unnecessary includes.
Back to your question you can use include, require, autoload or even phar. Probably PHAR is more close to C# libraries, you can include one PHAR libraries with a number of classes.
Put this in your config file( or any file included in all pages )
function __autoload($class_name) {
require_once "Classes" . $class_name . '.php';
}
Put every class in seperate file with its name.
replace "Classes" with your classes folder.
You can autoload classes. See:
http://us3.php.net/autoload
From that page:
<?php
function __autoload($class_name) {
include $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
Note that you can use spl_autoload_register() if you don't want to use the single magic __autoload function.
The autoloader will solve all your problems.
Autoloader, as others mentioned.
If you want to go step further... look at the way how Kohana (for example) solved the problem.
This question is the first Stack Overflow result from searching "php how to load classes" and other answers which provide examples for autoloading suggest the use of __autoload(). Please note that use of __autoload() is deprecated as of PHP 7.2 and its use is discouraged. Using spl_autoload_register is suggested instead.
The example snippet below is from the documentation page:
spl_autoload_register(function ($class_name) {
include 'classes/' . $class_name . '.php';
});

Is autoloader different for framework vs. normal library

According to the PCR-0 proposal, all the autoloader needs is autoload() function. Zend has a few autoloading classes
Zend_Loader()
Zend_Loader_Autoloader()
Zend_Loader_Autoloader_Resource()
Zend_Loader_Autoloader_Interface()
I'm guessing it has all these classes because it's a framework, so it needs to load its own classes, as well as library classes for any libraries that the developer may add and which don't have their own autoloader.
I have a library (normal library, not a framework). Right now it doesn't have an autoloader so I use Zend's Zend_Loader_Autoloader_Resource ->addResourceType(). If I write an autoloader for it, which autoloader will be used: Zend's or the library? and do I have to implement an autoloader as complex as Zend's or a simple one like the PCR-0 example.
What happens in these cases
both framework and library have their own autoloader
framework has autoloader, but the library doesn't
framework has NO autoloader, and library has
I'd suggest sticking to direct path->class mapping and implementing your own autoloader like this:
class MyLib_Autoloader
{
public function __construct() {
spl_autoload_register(array($this, 'autoload'));
}
public function autoload($className)
{
if (substr($className, 0, 6) == 'MyLib_') {
include dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR strtr($className, '_', DIRECTORY_SEPARATOR) . '.php';
return true;
}
return false;
}
}
This will check if the class is from your namespace and load the file. Assumes your autoloader is in /some/path/MyLib/ -> the include path will be /some/path/MyLib/../MyLib/ClassName.php. You can also add more logic to strip the initial MyLib from the class name and get rid of that '..'.
Make sure to use only require. It's faster and the autoload function is not called more than once for each classname! :) No need to include_once/require_once/etc. Go with the fastest.
Usage is as simple as:
include '/some/path/MyLib/Autploader.php';
$loader = new MyLib_Autoloader();
The main question is : who/how will your library be used ?
If that is by you only, then use Zend's autoloader, this will save you time. You don't need to reinvent the wheel.
If you have to make you library public and used on different projects, then that may be a problem because it will force the users of your library to have Zend Framework too. So in that case, either you make your own autoloader, either you pick one of a framework/library but include it in your library (watch out for the licenses).
Now regarding the utilisation of the autoloaders : only the autoloaders that are registered will be called. If you have your own autoloader, but you didn't mention how to setup it in your documentation, the users of your code will never think of set it up, and then it won't be used.
So the basic answer is to say : use many autoloaders, register them all, and they will be all called and everything will work fine. But that may lead to conflicts, because one autoloader will try to load something that is supposed to be handled by another autoloader, so you have to be careful with that, and not abuse of them.

Categories