I have recently started with learning Swift for iOS development. I have a background in scripting languages, especially PHP. Seeing that it is emphasized using let to define a constant in favor of var to have the compiler optimize the resulting code, I wondered: is there an equivalent for PHP? Or does it simply not apply as PHP is not statically compiled?
I tried my luck at searching but found no satisfying information on that point.
No, you can't have locally scoped constants in PHP. All PHP constants are always globally visible. There is also no concept like immutable/mutable variables.
You can implement immutable object members (PHP: immutable public member fields), but it's a different thing.
Actually there is a const keyword in the language, but the docs say:
Note:
As opposed to defining constants using define(), constants defined using the const keyword must be declared at the top-level scope because they are defined at compile-time. This means that they cannot be declared inside functions, loops, if statements or try/ catch blocks.
(from http://php.net/manual/en/language.constants.syntax.php)
Interpreted languages with a dynamic type systems can have something like the swift let statement, so this is not because swift is compiled and PHP is interpreted (for example, there is a javascript proposal to introduce that feature: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Statements/const)
Is there an equivalent of “let” vs. “var” in PHP?
PHP doesn't have let as a native language feature, yet (as of current version 7.1.4 - 04/2017)
But, some high-performance extensions like Phalcon and Ice have support for let, because of the underlying usage of zephir-lang.
So, there is let, but indirectly; using the above mentioned extensions.
There are two use cases:
define a variable from a super global
define a variable in the local PHP symbol table, e.g.
// set variable $price in PHP
let name = "price";
let {name} = 10.2;
As an example take a look at the source for the Ice Router:
namespace Ice\Mvc\Route;
use Ice\Mvc\Route\Parser\ParserInterface;
use Ice\Mvc\Route\DataGenerator\DataGeneratorInterface;
use Ice\Mvc\Route\Parser\Std;
use Ice\Mvc\Route\DataGenerator\GroupCount as Generator;
class Collector
{
private routeParser { set };
private dataGenerator { set };
/**
* Constructs a route collector.
*
* #param RouteParser $routeParser
* #param DataGenerator $dataGenerator
*/
public function __construct(<ParserInterface> routeParser = null, <DataGeneratorInterface> dataGenerator = null)
{
if !routeParser {
let routeParser = new Std();
}
if !dataGenerator {
let dataGenerator = new Generator();
}
let this->routeParser = routeParser,
this->dataGenerator = dataGenerator;
}
/**
* Adds a route to the collection.
*
* The syntax used in the $route string depends on the used route parser.
*
* #param string|array $httpMethod
* #param string $route
* #param mixed $handler
*/
public function addRoute(var httpMethod, string route, handler = null)
{
var routeDatas, routeData, method;
let routeDatas = this->routeParser->parse(route);
if typeof httpMethod == "string" {
let method = httpMethod,
httpMethod = [method];
}
for method in httpMethod {
for routeData in routeDatas {
this->dataGenerator->addRoute(method, routeData, handler);
}
}
}
/**
* Returns the collected route data, as provided by the data generator.
*
* #return array
*/
public function getData()
{
return this->dataGenerator->getData();
}
}
Related
I have been reading through some PHP code and I'm confused about one thing. I'm sorry if it may be basics, but I couldn't find anything about this (tbh no idea how to search for it).
there is a time where they use "_user". I have found out that it refers to class USER. However, I can't find anywhere where they refer _user to the USER class.
Does the underscore _ has a special meaning?
where and how did they link USER class with _user?
order.php file:
class ORDER
{
// order properties
private $_db = null;
private $_settings = null;
private $_user = null;
private $_userLevel = 1;
...
/**
* Order Constructor
* #param $db
* #param $settings
* #param $user
* #param $need_db_record
* #return ORDER
*/
public function __construct(&$db, &$settings, &$user, $need_db_record=false, $check_user_change = true)
{
$this->_db = $db;
$this->_settings = $settings;
$this->_user = $user;
...
}
/**
* Returns class instance
* #return USER
*/
public function user()
{
return $this->_user;
}
1) Some people use an underscore before variable names to denote a private variable. This is just a convention though and has no effect on the functionality of the code. If you want to know more about visiblity of variables, see: http://php.net/manual/en/language.oop5.visibility.php.
2) This question can not be answered without us seeing more of the code. Somewhere in the class there is either a setter method for $_user or it gets set in the constructor of the class. Since it seems to be private, these are are the only two options. <- More code was provided. New answer:
2) The variable $user is introduced via the constructor of the class ORDER. Somewhere in your code you will find the class USER, which describes how the object $user is built. If you want to know from where exactly $user is coming, search for "new Order(" in your code. You will find all places, where ORDER instances are created and you will see the arguments that are used. You can do the same with "new User(" and you will find all the places where USER instances are created.
If you are new to OOP I propose you read some introductory articles. You can start with the article from the PHP site itself: http://php.net/manual/en/language.oop5.php or look for some online courses or tutorials, like for example: https://www.codecademy.com/courses/web-beginner-en-bH5s3/0/1
An important aspect of the ORDER class you provided is that the variables $db, $settings and $user are given as references. That means if one would manipulate anything on the $db instance, these changes would be global. Chances are there is only one instance of $db, $settings and $user in the system, which are passed around by reference. See also: http://php.net/manual/en/language.references.pass.php
Note: To prevent downvotes because good practice might be opinion based - you can also rephrase the question as: What are the downsides of type-checking return values to compensate PHP's lack of generics? (I didn't use that as it implies that there are downsides).
Question
Coming from a Java/C# world, PHP's loose type handling has always been somewhat annoying. It got better when type-hinting for input parameters was introduced but I'm still missing generics and type-hinting for return values.
I find myself to occasionaly work around that by explicitly checking types within my code - which feels somewhat wrong since the language itself could handle it for me - and I would like to push these questions to the community:
Is type-checking return values a good practice to compensate PHP's lack of generics?
Is there a better/more standard way to do this?
Are genericts currently discussed for future implementation in PHP?
Example
To get a better idea why that is problematic, consider the following example:
Assume we are building a framework to transform input data in some other ouput data. Examples:
Transform a string representing an XML document into a DomDocument into another string by selecting the title of said DomDocument by an xpath expression.
(string) $xml =[TransformToDomDocument]=> (DomDocument) $doc =[TransformToString]=> (string) $title
Now let's assume the input is not a string containing XML but Json (but holds otherwise the same data). We'd now want to transform the Json input into a Json object and selet the title by using a JsonPath expression.
(string) $jsonString =[TransformToJson]=> (Json) $jsonObject =[TransformToString]=> (string) $title
(Note: The second example should clarify that the whole framework should be really flexible.)
The transformation is performed by using a chain of adapter objects that handle the conversion from input to ouput:
interface AdapterInterface{
/**
* Transform some input data into something else.
* #param mixed $data
* #return mixed
*/
public function transform($data);
/**
* Set the Adapter that is used to preprocess the $data before calling $this->transform($data)
* #param AdapterInterface $adapter
*/
public function setPredecessorAdapter(AdapterInterface $adapter);
}
class XmlToDomDocumentAdapter implements AdapterInterface{
private $predecessor;
/**
* Transform an xml string into a DOMDocument.
* #param mixed $data
* #return DomDocument
*/
public function transform($data){
if($this->predecessor !== null){
$data = $this->predecessor->transform($data);
// At this point, we just have to "trust" that the predecessor returns a (string)
}
$doc = new DomDocument();
$doc->loadXml($data);
return $doc;
}
}
class DomDocumentToStringAdapter implements AdapterInterface{
private $xpathExpression;
private $predecessor;
/**
* Transform a DomDocument into a string.
* #param mixed $data
* #return string
*/
public function transform($data){
if($this->predecessor !== null){
$data = $this->predecessor->transform($data);
// At this point, we just have to "trust" that the predecessor returns a (DOMDocument)
}
$xpath = new DOMXpath($data);
$nodes = $xapth->query($this->xpathExpression);
if($nodes->length > 0){
throw new UnexpectedValueException("Xpath didn't match");
}
$result = $nodes->item(0)->nodeValue;
return $result;
}
}
Usage:
$input = "..."
$xmlToDom = new XmlToDomDocumentAdapater();
$domToString = DomDocumentToStringAdapter();
$domToString->setPredecessorAdapter($xmlToDom);
$output = $domToString->transform($input);
The problematic part occurs when an adapter relies on it's predecessor to return the right input.
if($this->predecessor !== null){
$data = $this->predecessor->transform($data);
// At this point, we just have to "trust" that the predecessor returns a (DOMDocument)
}
In C# I'd solve this problems by using generics:
interface AdapterInterface{
/**
* Tranform some input data into something else.
* #param mixed $data
* #return T
*/
public function T transform<T>(object data);
}
/* using it */
//...
if(this.predecessor !== null){
data = this.predecessor.transform<string>(data);
// we now know for sure that the data is of type 'string'
}
//...
Since generics are not supported in PHP, I'm asking myself if it's a good practice to add a type check after every call to transform($data) like this:
if($this->predecessor !== null){
$data = $this->predecessor->transform($data);
if(!is_string($data){
throw new UnexpectedValueException("data is not a string!");
}
// we now know for sure that the data is of type 'string'
}
My current workaround
Im currently using multiple interfaces to define the output of the transform method like this:
interface ToStringAdapterInterface extends AdapterInterface{
/**
* Transform some input data into something else.
* #param mixed $data
* #return string <<< define expected output
*/
public function transform($data);
}
interface ToDomDocumentAdapterInterface extends AdapterInterface{
/**
* Transform some input data into something else.
* #param mixed $data
* #return DOMDocument<<< define expected output
*/
public function transform($data);
}
In each transformer I make sure to accept only the suitable interface as predecessor:
class DomDocumentToStringAdapter implements ToStringAdapterInterface {
private $xpathExpression;
private $predecessor;
public function __construct(ToDomDocumentAdapterInterface $predecessor){
$this->predecessor = $predecessor;
}
// ...
}
I would follow your approach: test the return value data type of $this->predecessor->transform($data) and throw an exception if it was not what it was expected to be.
I don't know whether you could be interested about Hack programming language by Facebook:
Hack is a programming language for HHVM that interoperates seamlessly
with PHP. Hack reconciles the fast development cycle of PHP with the
discipline provided by static typing, while adding many features
commonly found in other modern programming languages.
I'd like to be able to do something like this:
class Circle {
const RADIUS_TO_CIRCUMFERENCE = M_PI * 2; // Not allowed
private $radius;
public function __construct( $radius ) {
$this->radius = $radius;
}
...
public function getCircumference() {
return $this->radius * self::RADIUS_TO_CIRCUMFERENCE;
}
}
But I can't create a class constant from an expression like that:
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 my question is: What's the best workaround for this limitation of PHP? I'm aware of the following workarounds, but are there any others which are better?
1. Create a property
class Circle {
private static $RADIUS_TO_CIRCUMFERENCE;
private $radius;
public function __construct( $radius ) {
$this->radius = $radius;
$this->RADIUS_TO_CIRCUMFERENCE = M_PI * 2;
}
...
public function getCircumference() {
return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE;
}
}
I don't like this, because the value of $RADIUS_TO_CIRCUMFERENCE can be changed, so it's not really a "constant".
2. Use define()
define( 'RAD_TO_CIRCUM', M_PI * 2 );
class Circle {
const RADIUS_TO_CIRCUMFERENCE = RAD_TO_CIRCUM;
...
public function getCircumference() {
return $this->radius * self::RADIUS_TO_CIRCUMFERENCE;
}
}
This is better, since the value is truly constant, but the drawback is that RAD_TO_CIRCUM has been globally defined.
A digression
I don't understand how this can work. (Edit: I've tested it, and it does work.) According to the Handbook of PHP Syntax:
The const modifier creates a compile-time constant and so the compiler will replace all usage of the constant with its value. In contrast, define creates a run-time constant which is not set until run-time. This is the reason why define constants may be assigned with expressional values, whereas const requires constant values which are known at compile-time.
The manual confirms that "constants defined using the const keyword ... are defined at compile-time".
In this bug report from 3 years ago, a member of the PHP team wrote:
For the class constant we need a constant value at compile time and can't evaluate expressions. define() is a regular function, evaluated at run time and can therefore contain any value of any form.
But in my example above, the value of RAD_TO_CIRCUM is not known at compile-time. So what is the compiler putting for the value of RADIUS_TO_CIRCUMFERENCE?
I'm guessing that the compiler creates some kind of placeholder for the value of RADIUS_TO_CIRCUMFERENCE, and at run-time, that placeholder gets replaced with the value of RAD_TO_CIRCUM. Might this placeholder be a kind of resource? If so, maybe this technique should be avoided? The manual says: "It is possible to define constants as a resource, but it should be avoided, as it can cause unexpected results."
3. Create a method
class Circle {
...
private static function RADIUS_TO_CIRCUMFERENCE() {
return M_PI * 2;
}
public function getCircumference() {
return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE();
}
}
This is my favourite workaround that I'm aware of. The value is constant, and it doesn't affect the global space.
Is there another workaround which is even better?
As of PHP 5.6, you can use math expressions in PHP constants, so this would work:
const RADIUS_TO_CIRCUMFERENCE = M_PI * 2;
I encountered this thread because my environment wasn't configured properly (was set to PHP 5.4 by accident), so don't forget to check your PHP version.
I would recommend this approach:
class Circle {
...
private function RADIUS_TO_CIRCUMFERENCE() {
static $RADIUS_TO_CIRCUMFERENCE;
if ( null === $RADIUS_TO_CIRCUMFERENCE )
$RADIUS_TO_CIRCUMFERENCE = M_PI * 2;
return $RADIUS_TO_CIRCUMFERENCE;
}
public function getCircumference() {
return $this->radius * $this->RADIUS_TO_CIRCUMFERENCE();
}
}
The goal is calculation only once for all class entities, like a real constant.
In my case,
my installed php version is 7.1 but, in my IDE(PhpStorm) settings my php version 5.4 was selected. Once i've changed my php version the problem was gone.
PhpStorm settings->PHP and change the PHP language level and CLI interpreter php version.
If you agree to use a standard variable instead of const keyword :
class Foo {
public $CONST_A; // = calculation A // To let people quickly see the value.
public $CONST_B; // = calculation B
public static function initClass() {
self::$CONST_A = /* calculation A */;
self::$CONST_B = /* calculation B */;
}
}
Foo::initClass();
initClass() is done only once, when the class file is required.
Let's say I have a PHP class called Color, it's constructor accepts various params.
// hex color
$myColor = new Color('#FF008C');
// rgb channels
$myColor = new Color(253,15,82);
// array of rgb channels
$myColor = new Color(array(253,15,82));
// X11 color name
$myColor = new Color('lightGreen');
How should I use phpDoc to create API documentation for constructor and other methods like this?
How to use phpDoc with overloaded methods?
class Color {
/**
* Constructor
* what should be here?
*/
public function __construct() {
/* CODE */
}
}
Just my point of view, but you should not have multiple constructors in the first place - your constructor is going to be full of if/else-ladders, which really isn't a good idea, especially for something lightweight like a representation of a Color.
I strongly encourage you to try something like this instead:
class Color
{
protected function __construct($r, $g, $b)
{ ... }
public static function fromHex($hex) {
return new Color(...);
}
public static function fromRGB($r, $g, $b) { ... }
public static function fromArray(array $rgb) { ... }
...
}
Now, in consumer code, instead of somewhat mysterious and ambiguous constructor calls like these:
$a = new Color(0,0,0);
$b = new Color('#000000');
Instead you can have more legible and semantic consumer code, like this:
$a = Color::fromRGB(0,0,0);
$b = Color::fromHex('#000000');
This probably makes more sense to somebody reading the consumer code, it eliminates the logic required to make the ambiguous constructor work, and as a bonus (if you're using an IDE such as PhpStorm) you can have all your inspections pass. If you're running a documentation generator, this also ensures that all the options are documented individually, rather than lumped together in a verbal description.
Note that I declared the constructor protected - this is a personal preference, but if I'm going to have multiple static factory-methods, I prefer to see those consistently used in consumer code, rather than sometimes seeing Color::fromRGB(...) and other times new Color(...).
I think that is better to use #method annotation for class/interface, which declares overloading methods. This question is interesting for me too.
/**
* #method void setValue(int $value)
* #method void setValue(string $value)
* #method void setValue(string $value, int $startFrom)
*/
class Example
{
public function setValue($arg1, $arg2)
{
// ...
}
}
See http://phpdoc.org/docs/latest/references/phpdoc/tags/method.html
Because you allow variable length arguments there are two ways I would do this.
I would simply list the allowed arguments are parameters.
/**
* #param mixed $arg1 ... description
* #param mixed $arg2 ... description
* #param mixed $arg3 ... description
*/
public function __construct() {}
Or I would simply provide an explanation with some examples.
/**
* Explanation of different expected argument combinations.
*/
public function __construct() {}
Another alternative, since only one of the examples has more than one argument, would be to simply define the arguments in the method signature making the last 2 optional. Like this:
/**
* #param mixed $arg1 ...
* #param int $arg2 ...
* #param int $arg3 ...
*/
public function __construct($arg1, $arg2 = null, $arg3 = null) {}
I know of no elegant way to do this with phpDoc. The phpDoc comment/api formatting is based on a the Javadoc format. Javadoc doesn't have a feature set to support this because in java, if you want a method to have a variable number of arguments you re-declare the method prototype for each variation.
public double foo() {
}
public double foo(double my_param) {
}
So, my performance preference is to do something like
/**
* My General description
*
* Here explain what each argument combination can do
* #param mixed $arg1 can be array, string, hex as string, or int
* #param int $arg2 if arg1 is int, then this is etc, otherwise optional
* #param int $arg3 if ar1 is int, then this is etc, otherwise optional
*/
but this may not play nice with the various auto-documentation tools.
The according to Hoyle way to accomplish this can be found at the phpDoc site.
Is there a syntax for documenting functions which take a single configuration array, rather than individual parameters?
I'm thinking specifically of CodeIgniter-style libraries, which use a mechanism similar to this:
<?php
//
// Library definition
//
class MyLibrary {
var $foo;
var $bar;
var $baz;
// ... and many more vars...
/* Following is how CodeIgniter documents their built-in libraries,
* which is mostly useless. AFAIK they should be specifying a name
* and description for their #param (which they don't) and omitting
* #return for constructors
*/
/**
* #access public
* #param array
* #return void
*/
function MyLibrary($config = array()) {
foreach ($config as $key => $value) {
$this->$key = $value;
}
}
}
//
// Library usage:
//
// Iniitialize our configuration parameters
$config['foo'] = 'test';
$config['bar'] = 4;
$config['baz'] = array('x', 'y', 'z');
$x = new MyLibrary($config);
?>
So my question is, is there some supprted way of documenting the configuration array beyond just the purely textual description? Actually specifying a proper #param [type] [name] [desc] that allows PHPDoc to parse out useful values?
As an aside, CodeIgniter really does just overwrite it's own values with those passed in via the $config array as above, effectively allowing you to clobber private members. I'm not a fan, but I'm stuck with it.
I've never seen any "good" way of documenting this -- and I've never seen anything that could be used by IDEs (such as Eclipse PDT) for parameters hinting either :-(
I would have said "do like your framework does", but as you said, what it does, here, is not quite good enough...
Maybe a quick/sort list of possible keys might be better than nothing, though ; a bit like this :
#param array $config [key1=>int, otherKey=>string]
Not sure how it would be interpreted by phpDocumentor or an IDE... But might be worth a try ?
This is, btw, one reason why I tend to avoid that kind of way of passing parameters -- at least when there are not too many (optional) parameters to a method.
The correct array #param notation for arrays is as specified in PHPlint
You can use it to document a config array in a useful manner:
Example:
/**
* Does stuff
*
* #param array[int|string]array[string]Object $config
*
* #return array[int]string
*/
public function foo(array $config)
{
// do stuff here
return array('foo', 'bar', 'baz');
}
You can do this:
/**
* #param array $param1
* #param string $param1['hello']
*/
function hey($param1)
{
}
and netbeans will pick it up but phpdoc messes up the documentation
I always use <pre> tags in situations like this. Ex.:
/**
* #param array $ops An array of options with the following keys:<pre>
* foo: (string) Some description...
* bar: (array) An array of bar data, with the following keys:
* boo: (string) ...
* far: (int) ...
* baz: (bool) ...
* </pre>
*/
Most IDEs and documentation generators I have used seem to render this in a reasonable way, though of course they don't provide any type checking or inspection of the array parameters.
There is currently no "official" (as in 'supported by multiple tools') way to do this.
The PHP FIG is discussing it at the moment at https://groups.google.com/d/topic/php-fig/o4ko1XsGtAw/discussion
A text description, to whatever degree of completeness you want, is really your only option. You can make it as legible as you want, but code analysis tools (phpDocumentor, IDE support) have no way to know how your $array is actually structured at runtime.
I agree with the many commenters that writing code this way exchanges coding convenience for code legibility.
I've used classes.
<?php
class MyLibrary {
var $foo;
var $bar;
var $baz;
/**
* #param MyLibraryConfig|null $config
*/
function MyLibrary( $config = null ) {
if ( isset( $config->foo ) ) {
$this->foo = $config->foo;
}
if ( isset( $config->baz ) ) {
$this->baz = $config->baz;
}
if ( isset( $config->bar ) ) {
$this->bar = $config->bar;
}
}
}
/**
* #property string $foo
* #property int $bar
* #property array $baz
*/
class MyLibraryConfig {
}
It works fairly well, main problem is that the code becomes littered with specific classes. They can be nested so parts of configuration can be reused.