PHP: How to import sub-namespace in main namespace? - php

I am trying to find answer of following question:
Function world() is defined in the namespace 'myapp\utils\hello.' Your code is in namespace 'myapp'
What is the correct way to import the hello namespace so you can use the world() function?
Following is my code which I am trying but I am getting this error:
Fatal error: Call to undefined function myapp\world()
My Code:
<?php
namespace myapp;
use myapp\utils\hello;
world();
namespace myapp\utils\hello;
function world()
{
echo 'yes world';
}

You may do this:
<?php
namespace myapp;
\myapp\utils\hello\world();
namespace myapp\utils\hello;
function world()
{
echo 'yes world';
}
Also, read more here Using namespaces.
This is intresting:
All versions of PHP that support namespaces support three kinds of
aliasing or importing: aliasing a class name, aliasing an interface
name, and aliasing a namespace name. PHP 5.6+ also allows aliasing or
importing function and constant names.
Simply, before PHP 5.6, you can not use use to import a function. It has to be in a class. But with PHP5.6+, you can do this:
<?php
namespace myapp;
use function myapp\utils\hello\world;
world();
namespace myapp\utils\hello;
function world()
{
echo 'yes world';
}

<?php
namespace myapp;
use myapp\utils\hello\world;
But you miss the class name:
<?php
namespace myapp;
use myapp\utils\hello\world; // now, you can create an instance of world
class foo
{
public function bar()
{
return (new world())->yourMethod();
}
}
And your world class:
<?php
namespace myapp;
class world
{
public function yourMethod()
{
return 'It works';
}
}
Be sure that you've (auto)loaded the required classes!

Related

Is there a PHP namespace extension that allows you to import/use/alias functions as if it was extended?

Is there a PHP namespace extension that allows you to import/use/alias functions as if it was extended directly into the class rather your typical namespace'd silo?
main.php
<?php
namespace api;
class main extends core{
print $this->whoami; // prints computer
}
core.php i.e. class core holding basic functions / standards:
<?php
namespace api;
class core{
function __construct(){
$this->whoami = "computer";
}
}
I want to add modular like classes and or functions that can be directly access from the class i.e.,
function-addon.php:
<?php
namespace api;
function abc($a){
print $a;
}
function-class.php
<?php
namespace api;
class tools{
function tool_a( $a ){
return $a;
}
}
with main.php looking like this (non working sample below):
<?php
namespace api;
use function api\abc as abc;
use api\tools as tools;
class main extends core{
print $this->whoami; // prints computer
print $this->abc(5); // print 5 (desired access)
print tools::tool_a(10); //print 10
}
The goal is "$this->abc" access and not i.e., tools:tool_a.
As I experiment I have a working solution, but I'm not a huge fan of yet as it doesn't use namespaces / aliases.
<?php
namespace api;
require("function-addon.php");
class main extends core{
}
function-addon.php:
<?php
function abc($a){
print $a;
}
Which would then allow the following to work:
<?php
namespace api;
require("function-addon.php");
class main extends core{
function __call( $func, $arg ){
return $this->func($arg);
}
}
The above allows the magic __call function access the locally referenced function-addon.php file.
The solution here is PHP Traits (https://www.php.net/manual/en/language.oop5.traits.php)
Per #nice_dev reference, a PHP trait implements a way to reuse code.
function-addon.php:
<?php
namespace api;
trait tools{
function abc($a;){
return $a;
}
}
Which would then allow the following to work:
<?php
namespace api;
require("function-addon.php");
class main extends core{
use tools;
function __construct(){
$this->abc(5); //returns 5
}
}
Make sure you use namespace in your traits!
Since you're working all within in the same namespace, you don't actually need any imports.
Assuming you're using composer, note that psr-4 doesn't work on autoloading functions. But you can specify "files" to be autoloaded in your composer.json file.
For example you can use:
{
"autoload": {
"psr-4": {
"api\\": "api"
},
"files": ["api/abc.php"]
}
}
Now that we got that out of the way,
Let's say your main file is /index.php:
<?php
use api\main;
require __DIR__ . '/vendor/autoload.php';
echo main::abc(5); // 5
$main = new main();
$main->abc(6); // 6
echo $main->whoami; // computer
The main file would look something like this /api/main.php:
<?php
namespace api;
class main extends core {
public function __call($name, $arguments)
{
if(function_exists(__NAMESPACE__.'\\'.$name)) {
return call_user_func_array(__NAMESPACE__.'\\'.$name, $arguments);
}
}
public static function __callStatic($name, $arguments)
{
if(function_exists(__NAMESPACE__.'\\'.$name)) {
return call_user_func_array(__NAMESPACE__.'\\'.$name, $arguments);
}
}
}
core would look like this: /api/core.php:
<?php
namespace api;
class core{
function __construct(){
$this->whoami = "computer";
}
}
abc.php like this /api/abc.php:
<?php
namespace api;
function abc($a){
print $a;
}
But note that if you need to "import" from another namespace, then you'll probably run into trouble since you need a way to specify which namespace to import from. The imports list, to the best of my knowledge, is a shorthand to save you from typing out the full namespace of whatever you're "importing". But at runtime, the imports list no longer exists, and you can't, for example, use eval in order to take advantage of the import to turn a string like "abc" into "api\abc". You'd need another way to do this.
I'm not much of a fan of __call, and __callStatic, I'd sooner define the methods you're importing.
A good way to do this is through a trait.
Then when you import, you can use a trait, and it will be part of the class.
For example:
/api/xyz.php:
<?php
namespace api;
trait xyz
{
function xyz($a)
{
print $a;
}
}
Then you'd use it like so /api/main.php:
<?php
namespace api;
class main extends core {
use xyz;
}
Then index.php: /index.php
<?php
use api\main;
require __DIR__ . '/vendor/autoload.php';
$main = new main();
$main->xyz(7); // 7

How to get parent namespace from Trait

I created a trait and i want to be able to get the namespace of the class using the trait. is this possible? self::class gives me the class name of the parent but not the entire namespace
You can use ReflectionClass->getNamespaceName() with the reflection of self::class.
MyTrait.php
namespace MyTraitNamespace;
Trait MyTrait{
public function echoClassNamespace()
{
$ref = new \ReflectionClass(self::class);
echo $ref->getNamespaceName(); //Will echo MyClassNamespace
}
public function echoTraitNamespace()
{
echo __NAMESPACE__; //Will echo MyTraitNamespace
}
}
MyClass.php
namespace MyClassNamespace;
use MyTraitNamespace\MyTrait;
class MyClass{
use MyTrait;
}

namespace classes, functions and how to use

Decided to start using namespaces in my PHP projects and am struggling in getting this simple setup to work... What am I doing wrong?
First.php
<?php
namespace MyNamespace;
use PDO;
class First {
function hello() {
return 'hello';
}
}
Second.php
<?php
namespace MyNamespace;
use PDO;
use function \MyNamespace\First;
class Second {
function world() {
$firstpart = \MyNamespace\First::hello();
return $firstpart . ' world';
}
}
index.php
<?php
echo \MyNamespace\Second::world();
?>
This gives me an error:
Strict Standards: Non-static method MyNamespace\Second::world() should not be called statically in /var/www/testsite/index.php on line 2
Basically, I am looking for a way to call different functions in different classes within the same namespace. Have never used namespaces before and for the life of me however I try to call my functions, they end up giving me the same errors. Any pointers please?
Your error indicates an attempt to call a static method, which is not (class Second, method world - not static)
And importing function space names must be as follows:
First.php
<?php
namespace MyNamespace;
function hello() {
return 'hello';
}
Second.php
<?php
namespace MyNamespace;
use function \MyNamespace\First\hello;
class Second {
static function world() {
$firstpart = hello();
return $firstpart . ' world';
}
}
And use, for example:
Second::world()
(I add static word in declaration method world)
Read this

Call function from different class and namespace

I'm having some trouble to call a function from a namespaced class in a different namespaced class. In the dummy example below I would like to know how to use Class2 within Class1. I'm getting the error:
Trait 'name1\name2\Class2' not found in class1.php
The code:
#file index.php
require "class1.php";
require "class2.php";
$class1 = new name1\Class1();
$class1->sayHello();
#file class1.php
namespace name1{
class Class1{
use name2\Class2;
public function sayHello(){
echo Class2::staticFunction();
}
}
}
#file class2.php
namespace name2{
class Class2{
public static function staticFunction(){
return "hello!";
}
}
}
Thank you for any advice.
Ok, so you've got several errors which I have fixed.
Here's the working code you need:
# index.php
include "class1.php";
include "class2.php";
$class1 = new name1\Class1();
$class1->sayHello();
# class1.php
namespace name1;
use name2\Class2;
class Class1{
public function sayHello(){
echo Class2::staticFunction();
}
}
# class2.php
namespace name2;
class Class2{
public static function staticFunction(){
return "hello!";
}
}
Some explanations:
When in class definition the use is used for using traits and not namespace
In PHP namespace need not be enclosed in curly brackets
In PHP you include files with include, include_once, require, or require_once, and not import
Inside your first class, your trait is calling class2 as use name2\Class2 but, you are still within the name1{} namespace, so in reality you are calling it as: use name1\name2\Class2
So, you need to change
use name2\Class2; to use \name2\Class2
Try this.
namespace name1{
use \name2\Class2;
class Class1{
public function sayHello(){
echo Class2::staticFunction();
}
}
}
#file class2.php
namespace name2{
class Class2{
public static staticFunction(){
return "hello!";
}
}
}
Also, another tip: If you are separating your classes in separate files, you do not need to separate them as in they way you have done. Just call the namespace simple as:
// file1.php
namespace person;
class name{}
//file2.php
namespace address;
class name{}
Why not drop the static method and just inject the class? Seems like going through extra work for something so simple. That's what function arguments are made for.
namespace name1{
use \name2\Class2;
class Class1{
public function sayHello($Class2){
echo $Class2->someFunction();
}
}
}
namespace name2{
class Class2{
public function someFunction(){
return "hello!";
}
}
}
#index.php
include "class1.php";
include "class2.php";
$Class1 = new name1\Class1();
$Class2 = new name2\Class2();
$Class1->sayHello($Class2);
//hello!

How do namespace work in PHP

I'm trying to instantiate a class that use namespace.
<?php
namespace CFPropertyList;
require_once('CFPropertyList/CFPropertyList.php');
$plist = new CFPropertyList();
?>
That's working!
But when I try put that code into my class I get syntax errors. I can't use "namespace CFPropertyList;" in a class?
<?php
class Plist{
public function test(){
namespace CFPropertyList;
require_once('CFPropertyList/CFPropertyList.php');
$plist = new CFPropertyList();
}
}
?>
UPDATE:
Thanks to all I got this working.
<?php
namespace CFPropertyList;
require_once('CFPropertyList/CFPropertyList.php');
class Plist{
public function test(){
//some code
}
}
}
But is my own class in a namespace now? Sorry for the noob questions.
I can't do.
$plist = new Plist;
$plist->test();
Your namespace should be declared before your class, so the class would then belong to that namespace:
plist.php
<?php
namespace CFPropertyList;
class Plist{
public function test() {
echo 'Test';
}
}
?>
other.php
<?php
require_once('plist.php');
$plist = new CFPropertyList::Plist();
$plist.test();
?>
You have to put the namespace definition outside the class definition.
(Besides that your class definition seems to be pretty messed up. Don't you have any class methods?)
From Defining namespaces
Namespaces are declared using the namespace keyword. A file containing
a namespace must declare the namespace at the top of the file before
any other code - with one exception: the declare keyword.
So you must declare it at the top of the file.

Categories