I have found that writing PHP code within classes can become rather long:
$this->parser->parse_syntax($this->get_language_path($this->language),
$this->elements,
$this->regex);
For example, in Java a class instance can call its methods by name without referencing this, is there a way to achieve shorter code in PHP without using this and self every time you have to read a value?
No, in PHP if you want to run object's method or read/write property from inside of object you must write $this to refer that object instance.
PS. You can do at the beginning of each method something like this: $s = $this and use $s then, but it's strongly unrecommended, you shouldn't do that and it will be best, if you forget that you read this paragraph :)
I think it all comes down to your data structure, for instance your parse_syntax() method can default to $this->elements and $this->regex if null is passed instead:
class foo
{
public $parser = null;
public $language = null;
public $elements = null;
public $regex = null;
public function __construct()
{
$this->parser = new parser();
}
public function get_language_path($language = null)
{
$language = (isset($language)) ? $language : $this->language;
// your code here
}
}
class parser extends foo
{
public function parse_syntax($path = null, $elements = null, $regex = null)
{
$path = (isset($path)) ? $path : parent::get_language_path();
$elements = (isset($elements)) ? $elements : $this->elements;
$regex = (isset($regex)) ? $regex : $this->regex;
// your code here
}
}
Yes, Java does not always need this, it also does not need the $ in front of variables, and you use just one dot (.) instead of -> to reference object's variable.
But Python is still shorter than Java - you don't need to use braces in Python, then use Python.
Scala also much shorter than Java, so if you really need to write less code, then php is not the best choice.
Look into Python or Scala
Related
I have a the following class:
class MyClass {
public function __construct($id = 0, $humanIdentifier = '') {
$this->id = $id;
$this->humanID = $humanIdentifier;
}
}
So from my interpretation I should be able to pass either $id or $humanIdentifier to that constructor, neither or both if I wanted. However, when I call the code below I am finding that its the $id in the constructor args being set to hello world and not the $humanIdentifier, despite me specifying the $humanIdentifier when calling the constructor. Can anyone see where I am going wrong?
$o = new MyClass($humanIdentifier='hello world');
Edit: As of PHP8, named arguments are now supported. This wasn’t the case at the time of this post.
PHP does not support named arguments, it will set the value according to the order in which you pass the parameters.
In your case, you're not passing $humanIdentifier, but the result of the expression $humanIdentifier='hello world', to which $this->id is later set.
The only way I know to mimick named arguments in PHP are arrays. So you could do (in PHP7) :
public function __construct(array $config)
{
$this->id = $config['id'] ?? 0;
$this->humanId = $config['humanId'] ?? '';
}
Can anyone see where I am going wrong?
Yes, you think these are named parameters. They are not. They are positional parameters. So you'd call it like this:
new MyClass(0, 'hello world')
Adding support for named parameters has been suggested and rejected in the past. A newer RFC is proposed, but it still is to be refined and implemented.
You need to overload the constructor, but php does not have built-in functionality for it but there's a great workaround for it in documentation:
http://php.net/manual/en/language.oop5.decon.php#Hcom99903
Also here's a discussion why it might be a bad idea: Why can't I overload constructors in PHP?
like another answer said, php does not support named arguments. You can accomplish something similar with:
class MyClass {
public function __construct($args = array('id' => 0, 'humanIdentifier' => '') {.
// some conditional logic to emulate the default values concept
if(!isset($args['id'])){
$this->id = 0;
}else{
$this->id = $args['id'];
}
if(!isset($args['humanIdentifier'])){
$this->humanID = '';
}else{
$this->humanID = $args['humanIdentifier'];
}
}
}
you can then call it like:
new MyClass(array('humanIdentifier'=>'hello world'));
and the default id will be there. I am sure you can come up with some fancy iteration to accomplish this if there are enough parameters to make it worth while.
You can not create new object of class by this way:
$o = new MyClass($humanIdentifier='hello world');
You can use array as parameter of __construct:
class MyClass {
public function __construct(array $arg) {
$this->id = isset($arg['id']) ? $arg['id'] : 0;
$this->humanID = isset($arg['humanID']) ? $arg['humanID'] : 0;
}
}
Then you can create new object of class by this way:
$o = new MyClass(['humanId'=>hello world']);
How would I get something like this to work?
$class_name = 'ClassPeer';
$class_name::doSomething();
Depending on version of PHP:
call_user_func(array($class_name, 'doSomething'));
call_user_func($class_name .'::doSomething'); // >5.2.3
To unleash the power of IDE autocomplete and error detection, use this:
$class_name = 'ClassPeer';
$r = new \ReflectionClass($class_name );
// #param ClassPeer $instance
$instance = $r->newInstanceWithoutConstructor();
//$class_name->doSomething();
$instance->doSomething();
Basically here we are calling the static method on an instance of the class.
Use call_user_func. Also read up on PHP callbacks.
call_user_func(array($class_name, 'doSomething'), $arguments);
These answers are all outdated:
<?php
class MyTest{
public static function bippo(){
echo "hello";
}
}
$a = MyTest::class;
$a::bippo();
works fine
After I have almost missed the simplest solution from VolkerK, I have decided to extend and put it in a post. This is how to call the static members on the instance class
// calling class static method
$className = get_class($this);
$result = $className::caluclate($arg1, $arg2);
// using class static member
foreach ($className::$fields as $field) {
:
}
Reflection (PHP 5 supports it) is how you'd do this. Read that page and you should be able to figure out how to invoke the function like that.
$func = new ReflectionFunction('somefunction');
$func->invoke();
Documentation Link
if you need to adjust the namespace
$call = call_user_func(array('\\App\\Models\\'.$class_name, "doSomething"));
Can I assign to a property a value in the constructor, without define any parameter, using for instance an external function?
Example
function my_external_function() {
return 'Good Morning World';
}
class MyClass {
protected $_my_property;
public function __construct() {
$this->_my_property = my_external_function() != '' ? my_external_function() : 'Good night World!';
}
public function getOtherMethod() {
return $this->_my_property;
}
}
$obj = new MyClass();
echo $obj->getOtherMethod();
You can do this. The code in your question will work, but there is a problem with this approach.
If you write your class this way, it will always depend on that external function, but it will have no control over whether or not it even exists, let alone whether or not it will return a value the constructor can use. If you move, rename, or modify the external function, it could change the behavior of your class in unpredictable ways.
I would recommend something like this instead, which I think may accomplish what you're trying to accomplish (not sure) without forcing your class to blindly depend on an external function.
class MyClass {
protected $_my_property = 'Good night World!'; // set a default value here
public function __construct($x = null) { // give your constructor an optional argument
if ($x) { // use the optional argument if it's provided
$this->_my_property = $x;
}
}
public function getOtherMethod() {
return $this->_my_property;
}
}
You can still create an instance of your class with no argument
$obj = new MyClass();
and when you call $obj->getOtherMethod(); you'll get the default value.
You can still use the external function; just let it pass its value into your object's constructor instead of using it within the constructor.
$obj = new MyClass(my_external_function());
Yes, but you better avoid such tricky dependencies.
I want to use variables inside class names.
For example, let's set a variable named $var to "index2".
Now I want to print index2 inside a class name like this:
controller_index2, but instead of doing it manually, I can just print the var name there like this:
controller_$var;
but I assume that's a syntax error.
How can I do this?
function __construct()
{
$this->_section = self::path();
new Controller_{$this->_section};
}
It's a hideous hack, but:
php > class foo { function x_1() { echo 'success'; } };
php > $x = new foo;
php > $one = 1;
php > $x->{"x_$one"}();
^^^^^^^^^^^^
success
Instead of trying to build a method name on-the-fly as a string, an array of methods may be more suitable. Then you just use your variables as the array's key.
Echo it as a string in double quotes.
echo "controller_{$var}";
Try this (based on your code in the OP):
function __construct()
{
$this->_section = self::path();
$controller_name = "Controller_{$this->_section}";
$controller = new $controller_name;
}
You can do this.... follow this syntax
function __construct()
{
$this->_section = self::path();
$classname = "Controller_".$this->_section;
$instance = new $classname();
}
Another way to create an object from a string definition is to use ReflectionClass
$classname = "Controller_".$this->_section;
$reflector = new ReflectionClass($classname);
and if your class name has no constructor arguments
$obj = $reflector->newInstance();
of if you need to pass arguments to the constructor you can use either
$obj = $reflector->newInstance($arg1, $arg2);
or if you have your arguments in an array
$obj = $reflector->newInstanceArgs($argArray);
try this:
$name = "controller_$var";
echo $this->$name;
just to add on the previous answers, if you're trying to declare new classes with variable names but all the construction parameters are the same and you are treating the instanced object all alike maybe you don't need different classes but just different instances of the same.
I have this method :
public function getInstance()
{
$classname = $this->getFullyQualifiedClassName();
return new $classname();
}
Is there a way to write this without the $classname variable, which gets used only once?
You could use Reflection:
$reflectionClass = new ReflectionClass('SomeClassName');
$reflectionClass->newInstanceArgs(array(1, 2, 3));
But as far as I know, that will be a lot slower than the solution you already have. In a perfect world you could just write something like this:
return new ( $this->getFullyQualifiedClassName() )(); // THIS DOES NOT WORK!!!
But unfortunately PHP's syntax isn't very flexible, and therefore you have to create that ugly variable thats troubling you.
I just realized that there is another (very ugly) way to do it: eval:
return eval("return new ".$this->getFullyQualifiedClassName()."();");
I do not suggest that you used this though, because of the security risk that comes with using eval.
Give your getFullyQualifiedClassName method a parameter whether return object or string.
public function getFullyQualifiedClassName($return_object = false) {
//............
return $return_object ? new $classname() : $classname;
}
then
public function getInstance()
{
return $this->getFullyQualifiedClassName(true);
}
But I think this way is not better than your have a $classname in your getInstance method if your getFullyQualifiedClassName just need to return string of the class name.
Edit:
As #x3ro said, it violates the method name, another way is to use a Help method, but it still worth little. Actually the $classname is not so ugly.
public function getInstance()
{
return Util::NewObjectFromName($this->getFullyQualifiedClassName());
}