Lazy load class in PHP - php

I want to lazy load class but with no success
<?php
class Employee{
function __autoload($class){
require_once($class);
}
function display(){
$obj = new employeeModel();
$obj->printSomthing();
}
}
Now when I make this
function display(){
require_once('emplpyeeModel.php');
$obj = new employeeModel();
$obj->printSomthing();
}
It works but I want to lazy load the class.

__autoload is a standalone function not a method of a class. Your code should look like this:
<?php
class Employee{
function display(){
$obj = new employeeModel();
$obj->printSomthing();
}
}
function __autoload($class) {
require_once($class.'.php');
}
function display(){
$obj = new Employee();
$obj->printSomthing();
}
UPDATE
Example taken from the php manual:
<?php
function __autoload($class_name) {
include $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
?>

Change Employee a bit:
class Employee {
public static function __autoload($class) {
//_once is not needed because this is only called once per class anyway,
//unless it fails.
require $class;
}
/* Other methods Omitted */
}
spl_autoload_register('Employee::__autoload');

First if all it's better to use spl_autoload_register() (check the note in php's manual for autoloading).
Then back to your problem; only if the display() function is in the same directory as the employeeModel this will work. Otherwise, use absolute paths (see also include() and include_path setting

Related

Include file content into property?

I've a file called helper.php, in this file I've a list of functions (without class).
Now I need to include the content of helper file, into a property. For do this I've create a loader, this is an example:
class Loader
{
function include($helpName)
{
return include $helpName;
}
}
this Loader is used by my class like so:
class Foo
{
function __construct()
{
$this->load = new Loader();
$this->email = $this->load->include('helper.php');
$this->email->send();
}
}
unfortunately I get this error:
Fatal error: Call to a member function validate_email() on integer
if I print: var_dump($this->email); I'll get: int(1).
What am I doing wrong?
Unless you're specifically returning at the end of your class, it doesn't work that way. From the docs:
Handling Returns: include returns FALSE on failure and raises a warning. Successful includes, unless overridden by the included file, return 1.
I'd look into autoloading classes, or you can also create a class, and return that from your include.php.
public class Email
{
public function send()
{
echo 'Sending Email';
}
}
return new Email();
An example with autoloading:
//Create Email.php
public class Email
{
public function send()
{
echo 'Sending Email';
}
}
//Main file, set a register, so when it doesn't find a class, it will load from a file, and auto register it.
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});
class Foo
{
function __construct()
{
$this->load = new Loader();
//If Email class doesn't exist, it will load it from 'Email.php', and then initialize it.
$this->email = new Email();
$this->email->send();
}
}
Included code always runs in global scope. If you want your functions to be incorporated as methods of a class then you would need to create a new file wrapping the functions in
<?php
Class somename {
?>
And...
<?php
}
But writing self modifying code is inherently dangerous. And its ugly. And it will be sensitive to whether you explicitly end the included file with ?>
An alternative approach which sucks as much as that above, is to get a list of the defined functions, and invoke these from the _call() magic method:
Class somename {
public $included;
function _call($fn, $args)
{
return call_user_func_array($this->included[$fn]), $args);
}
}
$obj=new somename();
$before=get_defined_functions();
include('helper.php');
$obj->included=array_diff(get_defined_functions(), $before);
But you wil find that your included code will not run outside of a class if it references $this
Short version: do not do this

Included class inside another class is not declared PHP

I have the following __construct of a selfmade class;
public function __construct($ip, $user, $pass, $product) {
$this->_ip = $ip;
$this->_user = $user;
$this->_pass = $pass;
$this->_product = $product;
$this->ssh = new Net_SSH2($this->_ip);
if (!$this->ssh->login($this->_user, $this->_pass)) {
return 'Login Failed';
}
$this->sftp = new Net_SFTP($this->_ip);
if (!$this->sftp->login($this->_user, $this->_pass)) {
return 'Login Failed';
}
}
Now the problem is that it says Net_SSH2 and Net_SFTP is not declared, but I have included those classes at the page, im not sure, but can it be that I have to pass those classes into this class instead of just calling them?
If yes, how do I do that?
A better solution is to use autoload.
function __autoload($class_name) {
require_once $class_name . '.php';
}
Now, when you ask for a new class, it will be auto loaded.
Try this.
Have you included those classes using a require, include or an autoload function?
If you haven't, make sure the files in which those classes are defined are loaded.
Now, we need to check for the namespace.
At the top of the Net_SFTP, is there a namespace [SOMETHING]? If there is, you must refer to the fully qualified class name, or use this class.
An example:
<?php
namespace VendorName\BundleName;
class Net_SFTP {
....
}
?>
Now, in order to use this class, we must do one of the following:
<?php
use VendorName\BundleName\Net_SFTP;
...
$this->ssh = new Net_SFTP(...);
...
?>
Or, directly:
<?php
...
$this->ssh = new VendorName\BundleName\Net_SFTP(...);
...
?>

define class globally in withut require include

I want to define a class globally, so if I create a page this , it works
<?php
$cl = new MyOwnClass();
?>
How can I do that ?
You shoulod look into Autoloading Classes: http://www.php.net/manual/en/language.oop5.autoload.php
class classname
{
public function publicfuntioname($testvar) {
$this->testvar = $testvar;
}
}
Now include this file any where
$obj= new classname();
$obj->publicfuntioname("another value");

Forget late static binding, I need late static __FILE__

I'm looking for the get_called_class() equivalent for __FILE__ ... Maybe something like get_included_file()?
I have a set of classes which would like to know what directory they exist in. Something like this:
<?php
class A {
protected $baseDir;
public function __construct() {
$this->baseDir = dirname(__FILE__);
}
public function getBaseDir() {
return $this->baseDir;
}
}
?>
And in some other file, in some other folder...
<?php
class B extends A {
// ...
}
class C extends B {
// ...
}
$a = new A;
echo $a->getBaseDir();
$b = new B;
echo $b->getBaseDir();
$c = new C;
echo $c->getBaseDir();
// Annnd... all three return the same base directory.
?>
Now, I could do something ghetto, like adding $this->baseDir = dirname(__FILE__) to each and every extending class, but that seems a bit... ghetto. After all, we're talking about PHP 5.3, right? Isn't this supposed to be the future?
Is there another way to get the path to the file where a class was declared?
ReflectionClass::getFileName
Have you tried assigning it as a static member of the class?
<?php
class Blah extends A {
protected static $filename = __FILE__;
}
(Untested, and statics plus class inheritance becomes very fun...)
what if you don't use __FILE__ but a separate variable and set the variable to __FILE__ in each class
class A {
protected static $baseDir;
protected $filename = __FILE__; // put this in every file
public function __construct() {
}
public function getBaseDir() {
return dirname($this->filename) . '<br>'; // use $filename instead of __FILE__
}
}
require('bdir/b.php');
require('cdir/c.php');
class B extends A {
protected $filename = __FILE__; // put this in every file
}
$a = new A;
echo $a->getBaseDir();
$b = new B;
echo $b->getBaseDir();
$c = new C;
echo $c->getBaseDir();
you still have to redeclare the property in each class, but not the method
You could use debug_backtrace(). You probably don't want to, though.
Tested:
protected static $filename = __FILE__;
static::$filename
Doesn't work.
It looks like the constant is registered when the class is loaded which is not "late".
Not sure it was possible before, but what was best for me today is using reflection :
$basePath = new \ReflectionObject($this);
$dir = dirname($basePath->getFileName());

How can I call a static method on a variable class?

I'm trying to make some kind of function that loads and instantiates a class from a given variable. Something like this:
<?php
function loadClass($class) {
$sClassPath = SYSPATH."/classes/{$class}.php";
if (file_exists($sClassPath)) {
require_once($sClassPath);
$class = $class::getInstance();
}
}
?>
If I use it like this:
<?php
loadClass('session');
?>
It should include and instantiate the session class.
BTW: the static getInstance function comes from this code:
<?php
function getCallingClass() {
$backtrace = debug_backtrace();
$method = $backtrace[1]['function'];
$file = file($backtrace[1]['file']);
$line = $file[($backtrace[1]['line'] - 1)];
$class = trim(preg_replace("/^.+?([A-Za-z0-9_]*)::{$method}\(.*$/s", "\\1\\2", $line));
if(! class_exists($class)) {
return false;
} return $class;
}
class Core {
protected static $instances = array();
public static function getInstance() {
$class = getCallingClass();
if (!isset(self::$instances[$class])) {
self::$instances[$class] = new $class();
} return self::$instances[$class];
}
}
?>
The thing is that right now the way to use the functions in a class is this:
<?php
$session = session::getInstance();
?>
But now I want to build that into a function so that I never again have to use that line of code.
I just say loadClass('session');
and than I can use $session->blablablafunction();
Calling static functions on a variable class name is apparently available in PHP 5.3:
Foo::aStaticMethod();
$classname = 'Foo';
$classname::aStaticMethod(); // As of PHP 5.3.0
http://php.net/manual/en/language.oop5.static.php
Could definitely use that right now myself.
Until then you can't really assume that every class you are loading is designed to be a singleton. So long as you are using < 5.3 you'll have to just load the class and instantiate via the constructor:
function loadClass($class) {
$sClassPath = SYSPATH."/classes/{$class}.php";
if (file_exists($sClassPath)) {
require_once($sClassPath);
$class = new $class;
}
}
OR
Just load the class without creating an object from it. Then call "::getInstance()" on those meant to be singletons, and "new" on those that are not, from outside of the loadClass() function.
Although, as others have pointed out earlier, an __autoload() would probably work well for you.
You can use call_user_func():
$class = call_user_func(array($class, 'getInstance'));
The first argument is a callback type containing the classname and method name in this case.
Why not use __autoload() function?
http://www.php.net/autoload
then you just instantiate object when needed.
It looks like you are fighting PHP's current implementation static binding, which is why you are jumping through hoops with getCallingClass. I can tell you from experience, you should probably abandon trying to put instantiation in a parent class through a static method. It will cause you more problems in the end. PHP 5.3 will implement "late static binding" and should solve your problem, but that obviously doesn't help now.
You are probably better off using the autoload functionality mentioned by kodisha combined with a solid Singleton implementation. I'm not sure if your goal is syntactic sugar or not, but it think you will do better in the long run to steer clear of trying to save a few characters.
Off the top of my head, needs testing, validation etc:
<?php
function loadClass($className) {
if (is_object($GLOBALS[$className]))
return;
$sClassPath = SYSPATH."/classes/{$className}.php";
if (file_exists($sClassPath)) {
require_once($sClassPath);
$reflect = new ReflectionClass($className);
$classObj = $reflect->newInstanceArgs();
$GLOBALS[$className] = $classObj;
}
}
?>
Late static bindings will work for you I think. In the construct of each class do:
class ClassName
{
public static $instances = array();
public function __construct()
{
self::$instances[] = $this;
}
}
Then...
Here is an autoloader I created. See if this solves your dilemma.
// Shorten constants for convenience
define ('DS', DIRECTORY_SEPARATOR);
define ('PS', PATH_SEPARATOR);
$template = "default";
// Define an application path constants
define ('APP_ROOT', realpath('.').DS);
define ('VIEW', APP_ROOT . 'Views' . DS);
define ('MODEL', APP_ROOT . 'Models' . DS);
define ('CONTROLLER', APP_ROOT . 'Controllers' . DS);
define ('TEMPLATE', VIEW."templates".DS.$template.DS);
define ('CONTENT', VIEW."content".DS);
define ('HELPERS', MODEL."helpers".DS);
// Check if application is in development stage and set error reporting and
// logging accordingly
error_reporting(E_ALL);
if (defined('DEVELOPMENT')) {
ini_set('display_errors', 1);
} else {
ini_set('display_errors', 0);
ini_set('log_errors', 'On');
ini_set('error_log', APP_ROOT.'error.log');
}
$paths = array(APP_ROOT, VIEW, MODEL, CONTROLLER, TEMPLATE, CONTENT, HELPERS);
// Set the include path from Config Object
set_include_path(implode(PS, $paths));
// Autoloader
function __autoload($class)
{
require_once $class.'.php';
return;
}
Then all you have to do is
$var = new ClassName();
but you have to have a php file in the path with the name
ClassName.php
where ClassName is the same as the name of the class you want to instantiate.

Categories