I'm learning to use the namespaces in php, and I am trying to put a variable in the namespace name when calling a constant.
Here is my code.
fruits2.php
<?php
namespace fruits\red;
const redfruit = 'tomato';
fruits1.php
<?php
namespace fruits;
require_once('fruits2.php');
const myconst = 'banana';
echo myconst; // displays banana
echo '<br>';
echo \fruits\red\redfruit; // displays tomato
echo '<br>';
$color = 'red';
echo \fruits\$color\redfruit; // Parse error: syntax error, unexpected '$color' (T_VARIABLE), expecting identifier (T_STRING)
I don't understand how I can call the constant in this last line. I tried with the following but it is considered as a simple string.
echo '\fruits\\'.$color.'\\redfruit';
I'm pretty sure that I should be able to do it, because I could do something very similar when calling a class in another part of this code:
$name = '\fruits\basket\\'.$color.'\\eat';
$c = new $name(); //this works
Anybody knows the answer to that? Thanks!
Use the constant keyword:
$name = constant("fruits\\$color\\redfruit");
You have to escape the slashes.
Also the name has to be fully qualified (relative to the root namespace).
Related
<?php
namespace Vendor\Package;
$test1 = new Foo\Bar(); // works as usual
$test2 = 'Foo\Bar';
$test2 = new $test2(); // does not work
$test3 = 'Vendor\Package\Foo\Bar';
$test3 = new $test3(); // but this works
I was looking to use $test2 but it doesn't work even though it looks like it should as it's pretty much the same as $test3 which worked.
Is this expected or is there some syntax I need to use for test2 to work?
When you use a dynamic class name, it has to be fully qualified. The documentation says:
One must use the fully qualified name (class name with namespace prefix). Note that because there is no difference between a qualified and a fully qualified Name inside a dynamic class name, function name, or constant name, the leading backslash is not necessary.
Foo\Bar is not fully qualified, it's relative to Vendor\Package that you selected with the earlier namespace statement.
You can prefix your strign with __NAMESPACE__
Vendor\Package\Foo\Bar::__construct
Vendor\Package\Foo\Bar::__construct
Vendor\Package\Foo\Bar::__construct
Repl.it : https://repl.it/repls/BuzzingFairSuperuser
namespace Vendor\Package\Foo;
class Bar
{
function __construct()
{
echo __METHOD__,"\n";
}
}
namespace Vendor\Package;
$test1 = new Foo\Bar(); // works
$test2 = __NAMESPACE__.'\Foo\Bar';
$test2 = new $test2(); // works
$test3 = 'Vendor\Package\Foo\Bar';
$test3 = new $test3(); // works
So I'll see if I can explain this simply. In your first instance "$test1 = new Foo\Bar();", the path to the model is mapped during compile/load time. In the case where "$test2 = 'Foo\Bar'; $test2 = new $test2();", you're trying to call this model during runtime... Unfortunately, at runtime, the linking has already been done, and is not revisited. What this means it that "$test2 = '\Vendor\Package\Foo\Bar'" should work, but a shortened version of the name can't work, as the linking step is not revisited during runtime.
Is there a way to get fully qualified interface name similar to MyClass::class?
For example:
namespace Example\Tests;
use Example\Interfaces\InputInterface;
...
class CommandTest ...
...
public function createInputMock()
{
// I want to replace next string with something similar to MyClass::class
$this->getMockBuilder('Example\Interfaces\InputInterface')
...
Thank you.
The ::class name resolution can work with any imported namespaces: classes, interfaces, functions, ...
namespace A\B\C {
interface Interface_Bar {}
function Function_Foo() {}
function Function_Foo_Bar() {}
const Const_BARFOO = 123;
}
namespace {
use A\B\C\Interface_Bar;
use A\B\C;
use Undefined\Classes\UndefinedClass;
use function A\B\C\Function_Foo_Bar;
use const A\B\C\Const_BARFOO;
echo Interface_Bar::class, "\n"; // print A\B\C\Interface_Bar
echo C\Function_Foo::class, "\n"; // print A\B\C\Function_Foo
echo C\Const_BARFOO::class, "\n"; // print A\B\C\Const_BARFOO
echo UndefinedClass::class, "\n"; // print Undefined\Classes\UndefinedClass
echo Function_Foo_Bar::class, "\n"; // print Function_Foo_Bar <- warning
echo Const_BARFOO::class, "\n"; // print Const_BARFOO <- warning
}
If I got you right, you can't move to PHP 5.5 with ::class notation, so you want to have something similar in your 5.4 or earlier vesrion.
So the short answer is — no, there is no way.
The lack of this functionality in the previous versions of PHP is what made core developers to add ::class to PHP 5.5.
You can make a weird dirty hack if it's a class name: using get_class on new instance, but don't do it.
I'm experimenting with PHP 5.3's namespacing functionality and I just can't figure out how to instantiate a new class with namespace prefixing.
This currently works fine:
<?php
new $className($args);
?>
But how I can prepend my namespace in front of a variable classname? The following example doesn't work.
<?php
new My\Namespace\$className($args);
?>
This example yields: Parse error: syntax error, unexpected T_VARIABLE
Try this:
$class = "My\Namespace\\$className";
new $class();
There must be two backslashes \\ before the variable $className to escape it
Here's how I did it:
$classPath = sprintf('My\Namespace\%s', $className);
$class = new $classPath;
Note the single quotes instead of double.
In my PHP file I have created a class as below but I am getting error on line 3rd and 5th line.
class CommonPath{
var $baseurl = 'http://mysite.com/';
var $docroot = realpath(dirname(__FILE__));
var $root = '/';
var $images = $this->root.'/img';
}
My Dreamwaver CS5 showing these lines (3rd & 5th) as erroneous lines and I am getting following error on executing this code.
Parse error: parse error, expecting `','' or `';'' in D:\wamp\www\site\libs\CommonPath.php on line 3
You can have only literals and constants as default values. No functions or other expressions are allowed.
There are two different mistakes. First, you cannot use functions to define class variables (line 3). Moreover, $this does not make sense in line 5, as you have got no object yet.
You can't assign the values like that right when you're declaring your member properties. Assign it in the constructor
class CommonPath{
var $baseurl = 'http://mysite.com/';
var $docroot = '';
var $root = '/';
var $images = '';
function __construct() {
$this->docroot = realpath(dirname(__FILE__));;
$this->images = $this->root.'/img';
}
}
You can not concat string and assign any value to variable which need to call any function, at the time declaring class variable.
I know that you can create global constants in terms of each other using string concatenation:
define('FOO', 'foo');
define('BAR', FOO.'bar');
echo BAR;
will print 'foobar'.
However, I'm getting an error trying to do the same using class constants.
class foobar {
const foo = 'foo';
const foo2 = self::foo;
const bar = self::foo.'bar';
}
foo2 is defined without issue, but declaring const bar will error out
Parse error: syntax error, unexpected '.', expecting ',' or ';'
I've also tried using functions like sprintf() but it doesn't like the left paren any more than the string concatenator '.'.
So is there any way to create class constants in terms of each other in anything more than a trivial set case like foo2?
The only way is to define() an expression and then use that constant in the class
define('foobar', 'foo' . 'bar');
class Foo
{
const blah = foobar;
}
echo Foo::blah;
Another option is to go to bugs.php.net and kindly ask them to fix this.
Imho, this question deserves an answer for PHP 5.6+, thanks to #jammin comment
Since PHP 5.6 you are allowed to define a static scalar expressions for a constant:
class Foo {
const BAR = "baz";
const HAZ = self::BAR . " boo\n";
}
Although it is not part of the question, one should be aware of the limits of the implementation. The following won't work, although it is static content (but might be manipulated at runtime):
class Foo {
public static $bar = "baz";
const HAZ = self::$bar . " boo\n";
}
// PHP Parse error: syntax error, unexpected '$bar' (T_VARIABLE), expecting identifier (T_STRING) or class (T_CLASS)
class Foo {
public static function bar () { return "baz";}
const HAZ = self::bar() . " boo\n";
}
// PHP Parse error: syntax error, unexpected '(', expecting ',' or ';'
For further information take a look at: https://wiki.php.net/rfc/const_scalar_exprs and http://php.net/manual/en/language.oop5.constants.php
Always fall back to the trusty manual for stuff like this.
Regarding constants:
The value must be a constant
expression, not (for example) a
variable, a property, a result of a
mathematical operation, or a function
call.
So... "no" would be the answer :D
For class constants, you can't assign anything other than a constant expression. Quoting the PHP manual:
"The value must be a constant expression, not (for example) a variable, a property, a result of a mathematical operation, or a function call. "
This may not be directly what you're looking for, but I came across this thread, so here is a solution that I used for an issue I was having (based off of #user187291's answer):
define('app_path', __DIR__ . '/../../');
const APPLICATION_PATH = app_path;
.
.
.
require_once(APPLICATION_PATH . "some_directory/some_file.php");
.
.
.
Seems to work great!