Php require() does not recognize aliased class - php

So mainly this is caused by my code structure:
File1.php
use \Class1 as Blah;
require 'File2.php';
File2.php
$closure = function ($arg) {
return new Blah($arg);
};
Somehow the part behind ... as isn't recognized after using require().

Namespace aliases are only valid within the file in which you write the use statement. The aliases do not transfer across file boundaries. If you want to use Class1 as Blah within File2.php, you need to put that statement at the top of File2.php.

is not recognized by the code - Slim is not a compiler, it is a framework.
The code will execute to the PHP compiler standards, therefore using the default.
use SomeNamespace\SomeClass as SomePrefix;
Will work no matter what you're trying to achieve. The require_once() method loads your PHP file holding the class, which I assume doesn't have a custom namespace since you're targeting the \ directory.
If you're working inside a class then this might be your issue, your code should run similar to this after using the require_once() to load in the ParseMarkdownClass file.
use ParseMarkdownClass as Md;
class SomeClass
{
public $container;
public function __construct()
{
$this->container = (object)['m' => function() {
return new Md();
}];
}
}
(new SomeClass())->$container->m()->...

Related

import and alias a static method from a class

I am trying to alias a static method from a utility/helper class, the documentation does not give anything regarding static methods and using those defined there doesn't work for static methods (as it seems so).
So say I have this class:
namespace App\Helpers;
class HTTP {
public static function extract_path_from_url( string $url ) {
$parsed_url = wp_parse_url( $url );
if ( ! isset( $parsed_url['path'] ) ) {
return false;
}
return (string) $parsed_url['path'];
}
}
then trying to use it on a different file:
<?php
echo \App\Helpers\HTTP::extract_path_from_url( 'http://example.com/test' );
that one above works
but trying to alias it:
<?php
use \App\Helpers\HTTP\extract_path_from_url as extract_path;
echo extract_path( 'http://example.com/test' );
would output
Fatal error: Uncaught Error: Call to undefined function App\Helpers\HTTP\extract_path_from_url()
even:
<?php
use \App\Helpers\HTTP::extract_path_from_url as extract_path;
echo extract_path( 'http://example.com/test' );
shows this weird error:
Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)
Is this possible?
Regards,
Aliasing doesn't magically convert methods into functions, try this instead
<?php
use \App\Helpers\HTTP as extract_path;
echo extract_path::extract_path_from_url( 'http://example.com/test' );
Also (it should go without saying) when you alias this only affects the namespace and class name, not methods of the class. These are generally used for 1 of 2 things. Resolving naming conflicts
use NamespaceOne\Someclass;
use NamespaceTwo\Someclass as SecondClass;
If these were both put without an alias then using
Someclass::method()
Would be ambiguous.
The second thing they can be used for is if you need a lot of classes imported from one namespace. Such as this:
use App\Exceptions\NoFile;
use App\Exceptions\FileSize;
use App\Exceptions\FileType;
throw new NoFile();
throw new FileSize();
throw new FileType();
Can be done this way:
use App\Exceptions as E;
throw new E\NoFile();
throw new E\FileSize();
throw new E\FileType();
Which is not only shorter, but easier to maintain if you change the namespace you have to only change it for the alias and then all is good. So in short it's not really intended for what you want to use it for.
Wrap it
You can always make a wrapper for it:
if(!function_exists('extract_path_from_url')){
function extract_path_from_url($url){
return \App\Helpers\HTTP::extract_path_from_url($url);
}
}
And then call it to your hearts content. Performance wise you do have an extra call by wrapping it, but generally wrappers make it easier to maintain. For example if you rename that method or class, you can change it in the wrapper and everything is good. So there is an argument to be made for either option.
You don't have to check if the function exists, but depending on how your overall system works it may not be a bad idea, so I included it in the example just for the sake of completeness. Personally in a case like this, I don't see any issue putting it right in the same file with the class, just remember to load it. If you are using autoloading the functions won't be included unless you manually load the file or otherwise force it to autoload. Assuming nothing else uses the class first, of course.
One method I have used in the past that I really like, is to make a file named http_functions (classname + _functions) and then add a static method to the class that registers the functions:
class HTTP {
public static function regester_fuctions(){
require 'http_functions.php'
}
}
Then when you call HTTP::regester_fuctions() it autoloads HTTP class and includes all the functional wrappers. In fact I do this very thing in my really super awesome debug print class (queue shameless plug) https://github.com/ArtisticPhoenix/Debug
Just some thoughts, enjoy!
A workaround is to use a namespaced helpers.php file and define 'simple' functions in it, which simply pass through arguments.
// lib/My/Deeply/Nested/Namespace/MyClass.php
<?php
namespace My\Deeply\Nested\Namespace;
class MyClass
{
public static function aVeryUsefulFunction(string $var): string
{
// ...Do some stuff
return $magic;
}
}
// lib/helpers.php
namespace App;
use My\Deeply\Nested\Namespace\MyClass;
function doMagic(...$args)
{
return MyClass::aVeryUsefulFunction(...$args);
}
// templates/my-view.php
<?php use function App\doMagic; ?>
<div>I am doing <?= doMagic('magic') ?>!</div>
Note that by using the spread operator ...$args in my 'pass through' function I can change the requirements of the 'target' function without having to update it in two places.
This will break IDE completion, as it will only know to suggest ...$args rather than string $var. I don't know of a way to docblock a function to tell it to read parameters from another function.
As manual says you can import via use classes, functions and constants. Method of a class (even a static one) is not a function.
So, for example you have:
namespace My\Super\NameSpace;
const MY_CONST = 42;
class MyClass {
public function do() { /* code */ } // this is NOT a function
public static function doStatic() { /* code */ } // this is NOT a function too
}
function my_function() { /* code */ } // this is function
In some other file you can write:
namespace YaNamespace;
use const My\Super\NameSpace\MY_CONST;
use My\Super\NameSpace\MyClass;
use function My\Super\NameSpace\my_function as func_alias;
And that's all items you can import with use.

PHP: Understanding the include scope with spl_autoload_register

I'm trying to autoload Classes, but I'm hindered by the scope. The Class is being loaded, but I'm using it out of scope. Here's the code to further explain what I'm trying to do.
AutoLoader.php
<?php
class AutoLoader {
private $namespace;
public function __construct($namespace) {
$this->namespace = $namespace;
spl_autoload_register(array($this, 'ClassLoader'));
}
private function ClassLoader($class) {
$class = "classes/{$this->namespace}/{$class}.php";
print("Loading class: {$class}");
include "{$class}";
}
}
?>
script.php
<?php
ini_set("display_errors", 1);
$loader = new AutoLoader("myspace");
$MyClassObj = new MyClass();
$result = $MyClassObj->MyClassFun();
?>
So when it comes down to script.php, I get the print out that it's loading the class and I don't get any errors that it can't find the file. So it looks like it's loading, but when I use the class to create a new object, it tells me it can't find the class. So I'm loading the include out of scope.
I included the AutoLoader in a separate file so I could load it into multiple files. Am I able to make this work or must the AutoLoader be part of script.php instead of separate?
edit: Including error, added error display to script.php.
Loading class: classes/myspace/MyClass.php
Fatal error: Class 'MyClass' not found in /usr/local/apache2/htdocs/scripts/script.php on line 5
edit: Including MyClass.php and directory structure
MyClass.php
<?php
class MyClass {
public function MyClassFun() {
$var = "hello world";
return $var;
}
}
?>
Directory Structure
htdocs/scripts/script.php
htdocs/classes/myspace/MyClass.php
htdocs/AutoLoader.php
If I change the class to MyClasse (misspelled) it will error on the include because it can't find the file. So using the proper MyClass I can only assume that it's finding the file since it's not producing an error. So the include looks good, but it still won't use it.
Which, now that I think about it more, is strange. The include is only occuring because of line 5 when I go to use the class. ClassLoader is being called by the spl_auto_register to search for the class. It's finding and including the class. Yet the same line 5 fails to actually use it.
I guess I don't understand that disconnect. Line 5 is properly calling the ClassLoader, but then fails to actually find the class once loaded.

PHP Efficiency: Is it better to include at beginning of script or in function?

I am creating a project management system using a custom PHP MVC framework. I have a controller class that is responsible for handling projects. Naturally, one of the functions in my controller is createProject(). When a project is created, I need to send out an email so I also have a mailer class.
Is it more efficient to include('/model/Mailer.class.php'); at the beginning of the createProject() function, or at the beginning of the controller class containing the createProject() function and why?
My thought was that it would be more efficient to include it at the beginning of the createProject() function so that way it doesn't have to always be included when other functions are called that don't require it.
If you include the file at the beginning of class like:
include ('theFileClass.php');
class SomeClass{
//code ...
}
you can maintain the code more easily. On the other hand, if you include the file like this:
class SomeClass{
public function someMethod(){
include ('theFileClass.php');
//code ...
}
}
sometimes is considered a bad practice.
However, you will get a better performance if you use an autoload strategy and your code will be more readable and maintainable. Use spl_autoload_register instead of __autoload.
A little example:
//bootstrap.php
<?php
class Framework{
//code ...
public function createProject(){
//code ...
$mail = new MailerClass();
//code ...
}
//code ...
}
spl_autoload_register(function($class){
require_once 'path'. $class .'.php';
});

PHP - Is this good require_once or extends

I'm a newbie in php but I'll try to get straight to the point.
I have a class called ConnectionManager
class ConnectionManager
{
function ConnectToDB()
{
//PDO connection code
}
}
and in my other manager InstitutManager I am using require_once($filename) to get access to my ConnectionManager functions
require_once('../manager/ConnectionManager.php');
class InstitutManager
{
protected $connInstance;
function _construct()
{
$this->connInstance = new ConnectionManager;
}
function getInstituts()
{
$conn = $connManager->ConnectToDb();
//retrieve instituts
}
}
The question is : Should I be using extends ConnectionManager in my InstitutManager instead of require_once? Why should I use one more than the other?
Thanks
Edit : Changed code for InstitutManager class
Would this be ok like this? Or should I pass a pass a parameter with my connection already instanciated in function _construct($conn)?
Your include_once reads in a source file, which in this case has a class definition for ConnectionManager in it. Your extends sets up class InstitutManager as inheriting class ConnectionManager, i.e. InstitutManager gets everything in ConnectionManager and can then define its own modifications to that basic structure. There isn't really any relationship at all between the two operations, and your $connManager = new ConnectionManager operations are nonsensical.
require_once 'file'.php' just means that the PHP interpreter will take the contents of a file called file.php and dump it right there in the spot where the include was called. Kind of like what would happen if you would select everything in a Word file, click copy and paste it at the top of another Word file.
In your case you need to include the file, or else it will not know where to find the ConnectionManager class.

What's wrong with this PHP code snippet I found? I get undefined variable 'obj'

I would like just to like to ask for a little elucidation about this three code snippets I found and how PHP behaves with them:
1) a php class (tmp.class.php) with a static method call:
<?php
class Dummy {
public function sayHello()
{
echo "HELLO FROM DUMMY";
}
public static function requireScript() {
require __DIR__ . "/tmp2.php";
}
}
Dummy::requireScript();
2) another file (tmp1.php), instantiating the previous defined class:
<?php
require_once __DIR__. "/tmp.class.php";
$obj = new Dummy;
?>
3) another file (tmp2.php), using the previous instance of the class:
<?php
require_once __DIR__ ."/tmp1.php";
$obj->sayHello();
?>
Now I know that as the requireScript() method has a require call in it, in fact the tmp2.php is included twice, am I right? But when I make the script run (open the tmp2.php file in the browser) I get a Notice: Undefined variable: obj and then of course a Fatal error because of the sayHello();
Shouldn't the $obj be available to the second required tmp2.php script? What is wrong with this code?
Thanks for attention!
In fact noone should build PHP application in that way. You shouldn't put require / include in many files. In simple application you should run require / include at the beginning of file to have everything you need. In more complex applications you should simple use Object Oriented Programming and use autoloader to load classes definitions when they are needed

Categories