php method argument as enum/const - php

Is there a way to allow enum or const as method argument in PHP. In Qt/C++ you could use it like this, but ofcourse C++ supports that (language dependant).
Qt/C++/SslSocket
enum PeerVerifyMode {
VerifyNone,
QueryPeer,
VerifyPeer,
AutoVerifyPeer
};
void setPeerVerifyMode(QSslSocket::PeerVerifyMode mode);
I PHP I tried this:
First:
class Controller_My
{
const MENU_FRONT = 0;
const MENU_SESSION = 1;
public function render($menu_model)
{
$menu_model = intval($menu_model);
if( $menu_model === 0 )
$menu = new Model_Menu_Front();
if( $menu_model === 1 )
$menu = new Model_Menu_Session();
}
}
I've read also this post how to use constant from class as an argument definition in php function?. But even with http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism interface/implements solution if you are paranoined you use switch/if statement. Like this:
class EmployeeType...
int payAmount(Employee emp) {
switch (getTypeCode()) {
case ENGINEER:
return emp.getMonthlySalary();
case SALESMAN:
return emp.getMonthlySalary() + emp.getCommission();
case MANAGER:
return emp.getMonthlySalary() + emp.getBonus();
default:
throw new RuntimeException("Incorrect Employee");
}
}

Take a look at SplEnum and the user notes for an example.

Related

Create Enum from Name in PHP

In PHP 8.1, BackedEnum offer a from and tryFrom method to get an enum from a value. How can the same be achieved by non backed enums?
Example BackedEnum:
enum MainType: string
{
case Full = 'a';
case Major = 'b';
case Minor = 'c';
}
var_dump(MainType::tryFrom('a')); // MainType::Full
var_dump(MainType::tryFrom('d')); // null
However this doesn't exist for regular enums.
How would I retrieve a "normal" Enum by name, like:
enum MainType
{
case Full;
case Major;
case Minor;
}
$name = (MainType::Full)->name
var_dump(name); // (string) Full
One option I've found is to simply add a tryFromName function, accepting a string and looping over all the cases like this:
enum MainType
{
case Full;
case Major;
case Minor;
public static function tryFromName(string $name): ?static
{
foreach (static::cases() as $case) {
if ($case->name === $name) {
return $case;
}
}
return null;
}
}
$name = (MainType::Full)->name
var_dump(name); // (string) Full
var_dump(MainType::tryFromName($name)); // MainType::Full
This works, however it seams counter intuitive to enable a foreach loop going over all possibilities just to create an enum.
Therefore the question is, what is the right way to get an Enum in PHP from the name.
You can use Reflection:
trait Enum {
public static function tryFromName(string $name): ?static
{
$reflection = new ReflectionEnum(static::class);
return $reflection->hasCase($name)
? $reflection->getCase($name)->getValue()
: null;
}
}
enum Foo {
use Enum;
case ONE;
case TWO;
}
var_dump( Foo::tryFromName('TWO') ); // enum(Foo::TWO)
var_dump( Foo::tryFromName('THREE') ); // null
Works also for Backed Enums.
My two cents: My package https://github.com/henzeb/enumhancer does that for you, including several other things that might be useful.

Get enum value by name stored in a string in PHP

I want to get the value of an Enum in PHP by its name.
My enum is like:
enum Status : int
{
case ACTIVE = 1;
case REVIEWED = 2;
// ...
}
Status::from(2) can be used to get "REVIEWED", but how can I resolve the value from the name stored in a string ?
Well, it seems there is not any built-in solution in PHP. I've solve this with a custom function:
enum Status : int
{
case ACTIVE = 1;
case REVIEWED = 2;
// ...
public static function fromName(string $name): string
{
foreach (self::cases() as $status) {
if( $name === $status->name ){
return $status->value;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class );
}
}
Then, I simply use Status::fromName('ACTIVE') and get 1
If you want to mimic the from and tryFrom enum functions, you can also add:
public static function tryFromName(string $name): string|null
{
try {
return self::fromName($name);
} catch (\ValueError $error) {
return null;
}
}
You can use reflection for Backed case:
$reflection = new ReflectionEnumBackedCase(Status::class, 'REVIEWED');
$reflection->getBackingValue(); // 2
$reflection->getValue() // Status::REVIEWED if you need case object
Or enum reflection:
$reflection = new ReflectionEnum(Status::class);
$reflection->getCase('REVIEWED')->getValue()->value // 2
see also ReflectionEnumUnitCase
To get value from the name:
enum Status : int
{
case ACTIVE = 1;
case REVIEWED = 2;
// ...
}
print(Status::REVIEWED->value);
Enum documentation
I use a custom method too, but I return an enum.
The from method returns an enum, not a value. I think the fromName method should return an enum too. Then you have access to all methods of the enum. You don't need use another method - from.
public static function fromName(string $name): self
{
foreach (self::cases() as $status) {
if( $name === $status->name ){
return $status;
}
}
throw new \ValueError("$name is not a valid backing value for enum " . self::class );
}
public static function tryFromName(string $name): self|null
{
try {
return self::fromName($name);
} catch (\ValueError $error) {
return null;
}
}
The constant() function can return the value of a constant using a string variable.
This also applies to Enum class constants as mentioned in the basic enumeration section of the PHP Manual.
$name = 'REVIEWED';
$status = constant("Status::{$name}");
If anyone cares, I have created a library around that.
https://github.com/henzeb/enumhancer
Just add the trait to your enum
enum Status : int
{
use Henzeb\Enumhancer\Enhancers;
case ACTIVE = 1;
case REVIEWED = 2;
// ...
}
Status::get('ACTIVE');
Status::tryGet('ACTIVE');
You then don't have to use values at all. In that case you can also simply use from.
enum Status
{
use Henzeb\Enumhancer\Enhancers;
case ACTIVE;
case REVIEWED;
// ...
}
Status::from('ACTIVE')->key(); // returns 0
Status::tryFrom('Reviewed')->key(); // returns 1
It does so much more than that, but it defeats copying and pasting snippets around.

How to dynamically declare return type of function in PHP 7

I created method to dynamically go through object methods and create array with anonymous functions that will behave as factories.
I have a problem how to dynamically declare return type of anonymous function. I couldn't find the right syntax and I'm not sure if it's even possible in PHP.
I would like to create something like this in simplified version:
$services = [];
$object_class = get_class($object);
$method_names = get_class_methods($object_class);
// go through all object methods
foreach ($method_names as $method_name) {
// get return type of this method
$method = new ReflectionMethod($object_class, $method_name);
$type = $method->getReturnType();
// use it as return type for this anonymous function (not working)
$services[$method_name] = function() use ($object, $method_name): $type {
return call_user_func([$object, $method_name]);
};
}
But I'm getting syntax error here.
I'm not sure if this is possible, even with all the string magic PHP can do. What you could do is something like:
$result = call_user_func...;
return gettype($result) === $type ? $result : null;
or throw some exceptions if they do not match.

understanding __construct($foo = null) and check if $foo is true then

How $mysettings can be true while we are initializing it with null? is this a method to prevent SQL injection? It would be appreciated if you could explain the code below.
public function __construct($mysettings = null)
{
$this->shop_version = Mage::getVersion();
$this->moduleversion = Mage::getConfig()->getModuleConfig('Messagemodule')->version;
$this->apppid = Mage::getStoreConfig('magemessage/appId');
if (empty($this->apppid)) {
$this->apppid = 'no-appId';
}
$this->connectortype = ($settingvariable = Mage::getStoreConfig('Messagemodule/magemessage/connector', 0)) ? $settingvariable : 'auto';
if ($mysettings) {
$this->connectortype = $mysettings;
}
}
When you specify a default value in a PHP method (including a constructor), that's all it is - a default.
So if you have
class Foo {
public function __construct($mysettings = null) {
...
}
}
then you are providing two ways of constructing the class. You can either call
$foo = new Foo();
with no arguments, in which case $mysettings will be initialised to null. Or you can call
$settings = array('key' => 'value');
$foo = new Foo($settings);
in which case the $settings array will be passed into the new instance. The benefit this provides is that you don't need to provide an empty array to new instances for which you don't need custom settings; you can just omit the argument.
The check if ($mysettings)... in the class ensures that the settings are only used if they are provided - a PHP if statement can operate on lots of different types, not just booleans. In this case, if the variable is null, the condition will evaluate to false.
Have a look at this code:
<?php
function required($something)
{
echo $something;
}
required();
It throws a fatal error, because $something was required, but not passed. https://3v4l.org/fIKB9
Now look here:
<?php
function required($something = 'hello')
{
echo $something;
}
required();
required(' R.Toward');
Which outputs Hello R.Toward https://3v4l.org/nQF8r
So in essence, it is a way of setting a default optional value.

Define const as a variable

I looked up a few solutions, but nothing that's able to solve it. I realize that constants are not supposed to be modifiable hence the whole point of the word "constant".
In this case I'm dealing with an API class that goes like this
class GetAdGroups {
const CAMPAIGN_ID = "";
I have to pass a value to CAMPAIGN_ID, but it can't be hard coded as a string.
So the following is not an option:
const CAMPAIGN_ID = 123;
I tried going with "define"
class GetAdGroups {
$my_var = 123;
define("CAMPAIGN_ID", "$my_var");
But it throws an error and when I define it outside the class scope, it also throws an error that the constant is not found.
Not sure what else to try. Pretty new to OOP and would appreciate your help
Check this what are new features in php 5.6
<?php
const ONE = 1;
const TWO = ONE * 2;
class C {
const THREE = TWO + 1;
const ONE_THIRD = ONE / self::THREE;
const SENTENCE = 'The value of THREE is '.self::THREE;
public function f($a = ONE + self::THREE) {
return $a;
}
}
echo (new C)->f()."\n";
echo C::SENTENCE;
?>
this may help you. You can use expression as constant value here.
Note:-
It is now possible to provide a scalar expression involving numeric
and string literals and/or constants in contexts where PHP previously
expected a static value, such as constant and property declarations
and default function arguments.
Yes, this is quite impossible, even you can not do like
function bar(){
return 'Hi';
}
class C {
const SENTENCE = bar();
//const SENTENCE = :SELF:foo();
public static foo(){
return "Hello';
}
}
echo C::SENTENCE;
#u_mulder is very correct.
You have missed reading the documentation correctly.
/**
* This example gets all ad groups in a campaign. To get campaigns, run
* GetCampaigns.php.
*/
Check this class instead.
here your campaign id is variable.
foreach ($page->getEntries() as $campaign) {
printf(
"Campaign with ID %d and name '%s' was found.\n",
$campaign->getId(),
$campaign->getName()
);
}
If you are using PHP 7+ then you can use this way .
// Works as of PHP 7
define('ALLVAR', array(
'dog',
'cat',
'bird'
));
echo ALLVAR[1]; // outputs "cat"
If you are using php < 7 Then use this way .
define ("ALLVAR", serialize (array ('dog','cat','bird')));
$my_const = unserialize(ALLVAR);
Inside your Class you can define a function for constants. Like below
class GetAdGroups{
public $options = array(
'app_id' => 'hello',
);
public function getConstant($key){
return $this->options[$key];
}
}
$a = new GetAdGroups();
print_r($a->getConstant('app_id'));

Categories