I am getting an error:
Fatal error: Constant expression contains invalid operations in
config.php on line 214
That line was:
protected static $dbname = 'mydb_'.$appdata['id'];
Whether I did any mistakes in quotes? Or somewhere else?
My search for the error message only showed a different source cause (a dynamic default value in a function definition).
asked Oct 21, 2016 at 8:13
3
From the official Php documentation :
Like any other PHP static variable, static properties may only be initialized using a literal or constant before PHP 5.6; expressions are not allowed. In PHP 5.6 and later, the same rules apply as const expressions: some limited expressions are possible, provided they can be evaluated at compile time.
So you cannot initialize a static variable with another variable. Replace $appdata['id'] with a constant string or remove the static attribute.
This is because all static declarations are resolved in compile-time, when the content of other variables is not known (see this other page of official doc).
Aslamkv
5191 gold badge5 silver badges7 bronze badges
answered Oct 21, 2016 at 8:22
Al Foиce ѫAl Foиce ѫ
4,12512 gold badges39 silver badges49 bronze badges
2
Unless you mess with reflection, the only way I can think of to have a static private/protected class property with a dynamically generated value is to calculate it outside the class:
class Foo
{
protected static string $dbname = DBNAME;
public static function debug(): string
{
return Foo::$dbname;
}
}
$appdata = [
'id' => 31416,
];
define('DBNAME', 'mydb_' . $appdata['id']);
var_dump(Foo::debug());
In your precise use case, however, it’s possible that there’s simply no good reason for the property to be static. In that case, it’s as straightforward as using the constructor:
class Foo
{
protected string $dbname;
public function __construct(array $appdata)
{
$this->dbname = 'mydb_' . $appdata['id'];
}
public function debug(): string
{
return $this->dbname;
}
}
$appdata = [
'id' => 31416,
];
$foo = new Foo($appdata);
var_dump($foo->debug());
answered Oct 21, 2016 at 11:34
Álvaro GonzálezÁlvaro González
139k39 gold badges258 silver badges351 bronze badges
4
This is because a static variable contains a constant value in it. But in your case:
protected static $dbname = 'mydb_'.$appdata['id'];
$appdata['id'] is dynamic that can change its value during the execution. That’s why the error is showing.
answered Oct 21, 2016 at 8:22
Mayank PandeyzMayank Pandeyz
25.3k4 gold badges37 silver badges58 bronze badges
2
I had this error and my fix was to not declare a date within a class property array
public static $config_array = array(
'start_date' => date('Y-m-d H:i:s') // No can do
);
answered Mar 23, 2017 at 15:26
JackJack
3,22510 gold badges47 silver badges57 bronze badges
For your information:-
I got the same error by using some characters in a constant expressions.
public static $dbPassword="mAkE-34@-||sR";
This is what caused the error and I removed this || which is the logical OR operator characters from the string and it worked.
answered Aug 31, 2021 at 11:48
I have the following code, where I get the error «PHP Fatal Error: Constant expression contains invalid operations». It works fine when I define the variable in the constructor. I am using Laravel framework.
<?php
namespace App;
class Amazon
{
protected $serviceURL = config('api.amazon.service_url');
public function __construct()
{
}
}
I have seen this question: PHP Error : Fatal error: Constant expression contains invalid operations
But my code does not declare anything as static, so that did not answer my question.
Jac
1,0848 silver badges16 bronze badges
asked Nov 27, 2016 at 10:24
2
As described here
Class member variables are called «properties». You may also see them referred to using other terms such as «attributes» or «fields», but for the purposes of this reference we will use «properties». They are defined by using one of the keywords public, protected, or private, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value—that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
The only way you can make this work is :-
<?php
namespace App;
class Amazon
{
protected $serviceURL;
public function __construct()
{
$this->serviceURL = config('api.amazon.service_url');
}
}
answered Nov 27, 2016 at 11:57
prateekkathalprateekkathal
3,3821 gold badge19 silver badges38 bronze badges
0
Initializing class properties is not allowed this way. You must move the initialization into the constructor.
answered Nov 27, 2016 at 10:30
MananManan
8899 silver badges11 bronze badges
0
Another working alternative I used is with boot( ) with Laravel Eloquent:
<?php
namespace App;
class Amazon {
protected $serviceURL;
protected static function boot()
{
parent::boot();
static::creating(function ($model){
$model->serviceURL = config('api.amazon.service_url');
});
} }
answered Jul 14, 2018 at 15:46
4givN4givN
2,7961 gold badge21 silver badges50 bronze badges
Содержание
- Fatal error: Constant expression contains invalid operations почему?
- Want to Keep in touch with us, subscribe to our newsletter !
- Prepare for PHP 7 error messages (part 2)
- Prepare for PHP 7 error messages
- « Return value of %s%s%s() must %s%s, %s%s returned »
- « Cannot declare a return type of %s outside of a class scope »
- « Constructor %s::%s() cannot declare a return type » « Destructor %s::%s() cannot declare a return type » « %s::%s() cannot declare a return type »
- « Constant expression contains invalid operations »
- « Constants cannot be recursive arrays » « Constants may only evaluate to scalar values or arrays »
- « Cannot use temporary expression in write context »
- To be continued
- Почему один и тот же PHP код вызывает синтаксическую ошибку?
Fatal error: Constant expression contains invalid operations почему?
Ругается на строчку, где переменной присваиваю адрес. понять проблему ошибки не смог. констант нет в классе. это мои первые шаги, помогите разобраться.
- Вопрос задан более трёх лет назад
- 4988 просмотров
Обращаешься к какой-то неопределенной переменной. Если нужно обратиться к переменной экземпляра класса
или к переменной класса
Ах ну да, ниже посмотрел на конструктор. Если хочешь передавать id, тогда так
Евгений, я поправил под твой вариант всё)
когда пишет $test = new Pars() — в скобки передаешь то, что передаешь в __construct, в данном случае надо передать id.
Если конструктора нет, скобки ставить не надо.
Конструктор нужен тогда, когда надо создать экземпляр класса. Т.е. можно написать
и у каждого экземпляра ($test, $test2) будет свой url, id. Потому что $this ссылается именно на экземпляр. Т.е. $this->get задает $get именно для $test, или $test2, в зависимоти от того, какой экземпляр.
В то же время есть статика, т.е. можно прописать
public static $url = 123;
Тогда можно обращаться Pars::$url.
static — это константа для данного класса.
VicTHOR, еще вопрос — передавать в функцию можно переменные, которые объявлены непосредственно в классе? вот только с $id не понял. это как-бы мы делаем что-то подобное:
$this->id = $id; //присвоили переданный id экземпляру класса — вот этой строкой?
Евгений, в какую функцию? в конструктор? Только то, что принимает конструктор
__construct( id ) — передаем только id
$this->id = $id аналогично $test->id = $id или $test2->id = $id
можно не объявлять переменные до конструктора, достаточно в конструкторе указать. А можно не указывать конструктор, можно функций понаписать в классе и к ним обращаться, не имея переменных.
Я указал только private $url, что-бы нельзя было обратиться к $test->url
В таком случае обращение к $test->url происходит непосредственно в самом классе, т.е. когда прописывается $this->url
т.е. я отдельно от конструктора явно указал, что url в этом классе приватный.
советую тренироваться в какой-нибудь песочнице, так быстрее все затестишь и освоишь
Источник
Want to Keep in touch with us, subscribe to our newsletter !
- Features
- What is static analysis ?
- Detect Tricky Issues
- Fix Automatically Code
- Prevent security issues
- Integrate in your CI
- Control the quality
- Leverage on Methodology
- Developers
- Price & Services
- Self-Hosted
- Blog
Company
Prepare for PHP 7 error messages (part 2)
Prepare for PHP 7 error messages
In the article “Prepare for PHP 7 error messages (part 1)” from last week, we covered the evolution of error messages in the PHP binary. In order to prepare for prepare for PHP 7 error messages, we are now going to review the new messages that are appearing in PHP 7. We’ll also see some of those that are disappearing : it’s good to know we won’t meet them again.
« Return value of %s%s%s() must %s%s, %s%s returned »
The first extra error messages is linked to the new feature called Return Type Hint. This works like Type Hint, but is applied to returned values. At definition time, it is possible to specify which type of value will be returned. This is achieved by adding a colon and a type hint after the function signature :
The error message will be thrown anytime the return value doesn’t match the specified return type hint. Both Type Hinting (in- and outgoing) aims at enforcing that correct values are passed in and out in a method. Libraries will probably be keen on adopting them, leading to a transition phase where lots of this error message have to be cleaned.
« Cannot declare a return type of %s outside of a class scope »
Linked to the previous, it is possible to use the special keywords ‘self’ and ‘parent’ when defining a Type Hint (‘static’ is not supported). This error message will be emitted if a function makes use of them : only methods, inside a class, can use them. The error will be raised at execution time : linting can’t spot that.
« Constructor %s::%s() cannot declare a return type »
« Destructor %s::%s() cannot declare a return type »
« %s::%s() cannot declare a return type »
There are some methods that doesn’t require a Return Type hint : Constructor, Desctructor and __clone. All of them are called at object initialization, and no returning value is actually expected : the most important is the process to build (or unbuild) the new object. As such, Return Type Hint are useless in those methods.
PHP 4 constructors are also supported, and it will be fun to find code that mix emerging Return Type hint feature with legacy PHP 4 constructor. Mail me when you find one.
Note that return inside such method are also unused, but do not generate any error message : one can use a return in a __construct, to interrupt the method early. The returned value, often a null, will just be ignored.
« Constant expression contains invalid operations »
This message will help everyone who is using the recent Constant Scalar expression. This new features allows a certain number of operations to be performed when creating a new constant. For example,
So, most operators are allowed, including ternary operator, logical, comparison, array pair and math operations but not assignations.Variables are all forbidden but normal, magic and class constants are valid. Functioncall are forbidden except array(). More about this : https://wiki.php.net/rfc/scalar_type_hints_v5
This message is one of the direct advantages of the new AST in PHP : where PHP 5.6 is emitting an fatal error because it has reached an error, the AST allows PHP to check the situations and validate it graciously.
« Constants cannot be recursive arrays »
« Constants may only evaluate to scalar values or arrays »
Those errors are also better messages linked to the creation of constants based on structure that can’t be constants, such as objects, resources or recursive arrays. This last one is an array which contains a reference to itself. PHP 7 accepts arrays with references, though they will be dropped by the constant, and only values will be kept.
« Cannot use temporary expression in write context »
The AST is also at the origin of this new message : with the universal variable syntax, some situations are now possible, like nesting :: ($foo::$bar::$baz) or using immediately some object without storing it (new someClass)().
Some newly supported situations will then generate errors, like ‘foo'[0] = ‘b’. This instruction changes the first character for the string ‘foo’, but since the string is not stored in a variable, the result is lost anyway. The result is not necessarily lost, since such expression could be nested in a parenthesis and assigned like $x = (‘foo'[0] = ‘b’) ;. PHP 5.6 doesn’t accept anything like that (fails with a fatal error), so it old code may not generate such errors.
The list of situations that will lead to this error are not explicit (yet), though there are 34 occurrences of this message in the PHP source. Playing with too many literals will probably lead to it. Read more about this in https://wiki.php.net/rfc/uniform_variable_syntax.
To be continued
That will be all for this week. We’ll have another set of PHP 7 error messages next week.
Источник
Почему один и тот же PHP код вызывает синтаксическую ошибку?
Пишу вот такой кусочек кода:
Он работает, и выводит рандомные имена файлов.
Оформляю его же в виде класса:
Ошибка в строке инициализации var $fontFile.
Почему так? Как исправить?
С помощью var можно инициализировать только константные значения.
Так здесь инициализируется константа.
Но он же разный.
Выражение одно и то же.
Нет, значение будет разное в зависимости от рандома
Но оно же вычисляется до того, как будет инициализирована константа. Вычисляется выражение, и полученным значением инициализируется константа. В чем проблема?
Проблема в том, что его нельзя просто взять и вычислить, для этого нужно запускать код. Для этого есть конструкторы.
Как же его можно вычислить, если результат функции неизвестен на этапе компиляции?
С каких пор PHP стал компилируемым языком?
Наличие интерпретатора не означает отсутствие этапа компиляции.
Негоже быть таким безграмотным.
Вот это дельное замечание.
Конструктор бы трогать не хотелось.
Может быть, можно вычислить значение до определения класса и воспользоваться им в инициализации переменной? Что-то не получается у меня это сделать.
только хз работает или нет
Чем товй код отличается от моего?
У вас минимум 4 синтаксические ошибки. Как и у ТС.
не очень понятно чего он хочет в итоге добиться.
не многим, там тоже не правильно. Но примерно должно быть так,наверное.
Для начала http://php.net/manual/en/language.oop5.properties.php Там написано чем и почему нельзя инициализировать свойства класса. Да и про синтаксис почитать будет не лишним.
Без конструктора можно, но тогда будет совсем непонятно нафига тут класс. Например:
Или можно побороть первобытный страх перед конструкторами и написать так:
С каких пор PHP стал компилируемым языком?
Боюсь ошибиться, но вроде бы с 4 версии, когда появился Zend Engine.
Я похож на твою маму, которая бегает тебе готовить чай когда ты противным голоском этого требуешь? Ты явно меня с кем-то перепутал.
нет, благо моя мама не такая бесполезная как ты. =)
Комменты не читал но сразу скажу. Нельзя выполнять любые операции помимо присваивания вне конструктора или методов.
Я бесполезный потому что не метнулся выполнять твои хотелки или я бесполезный потому что ты глупый и пишешь невалидный код на языке, которого не знаешь?
Просто вынеси из своего выражения rand(0,3) во внешнюю констану (хоть через тот же define
ну так написал бы валидный код, на своем уровне чем сраться как сам и написал с таким «глупым школьником».
То есть мой ответ выше был тебе.
Правильный ответ дан в первом же посте, что ты собрался писать и зачем?
Хотела и написала, так же как и ты по неведомой причине решил оскорбить меня.
Может быть причина в том, что это не он, а она? Ну хочется ей быть полезной, да не умеет она, что поделаешь.
Так здесь инициализируется константа.
Это тоже не сработает. Если выносить во внешнюю константу, то всё выражение array(‘caveman.gdf’, ‘automatic.gdf’, ‘bubblebath.gdf’, ‘crass.gdf’)[rand(0,3)])
Но это дурь, ИМХО.
Конструктор бы трогать не хотелось.
Дельный совет уже дали. Выносить все это во внешние константы – бред какой-то. Делай все внутри конструктора, да и если ты захочешь использовать этот список шрифтов в другом месте или изменить – один фиг будешь доставать его из внешних конфиг приложения. Так что забей.
Разумеется, выносить константные выражения в константы — это бред. Надо же, чтобы они генерировались для каждого инстанса класса! А исходя из ТЗ ОП-посте, они должны генерироваться лишь единожды, при инициализации скрипта.
PHP Parse error: syntax error, unexpected ‘(‘ in sample_02.php on line 5
А почему это говно выплюнуло такую неочевидную ошибку? Выплюнуло бы что-то вроде: «non-static data member initializers isn’t available».
Надо же, чтобы они генерировались для каждого инстанса класса!
Нет, я вижу где конфигурируемый список и думаю, что как и для любого конфигуриремого списка ему место в конфиге приложения. Но я не байтодрочер, и понимаю, что здесь тег ООП и это PHP, а не С. И поэтому, думаю что даже мерзкие конфиги, а-ля
Потому что автор интерпретатора хотя бы знает английский, в отличие от дурака из России, который не способен ни в пых, ни в английский. English motherfucker! Do you speak it?
Потому что так универсальнее. Еще какие-то кучи типов ошибок придумывать, тьфу.
Ты поехавший. У тебя СПГС. Был вопрос конкретный. Без всяких потребнойстей к какой-либо архитектуре. Предложенное тобою решение генерировало бы случайный элемент из списка для каждого инстанса класса, в то время как исходя из исходного описания, этот случайный элемент списка должен быть одним для всех инстансов.
Если ты не понимаешь отличия переменной от константы, то мне страшно представить какой из тебя ахритектор.
Потому что у него версия php ниже седьмой. В седьмой все нормально описывается
Да, лан, даже perl иногда получше сообщает, где косяк:
А в остальном согласен.
для каждого инстанса класса
Если ты не понимаешь отличия переменной от константы, то мне страшно представить какой из тебя ахритектор.
О каких «каждых инстансах» ты говоришь? Если для тебя не очевидно, что для конфигурации приложения потребуется один единственный инстанс, то мне страшно представить какой из тебя программист.
А устанавливать константу RAND(0,3) только ради того, чтобы получить псевдорендомное значение из массива – это просто верх мысли, ага.
Ты какой-то агрессивный и унылый. Это всё из-за PHP, наверное. Программирование должно доставлять радость и лулзы.
Тебя когда спрашивают как инициализировать переменную, ты начинаешь рассказывать о масштабируемости и хай-лоаде? Ты здоров? Ты читать умеешь? В оп-посте где-то был вопрос о том, что это конфиг? Илио том, как ему хранить конфиг? Там вообще про конфиг и архитектурные решения какие-либо вопросы задавались?
Ваш helloworld.lang плохо поддается поддержке, надо срочно все переписать на %LanguageName% на основе %FrameworkName% с применением %TechnologyName%
В оп-посте где-то был вопрос о том, что это конфиг?
$fontFile = ‘fonts/’.array(‘caveman.gdf’, ‘automatic.gdf’, ‘bubblebath.gdf’, ‘crass.gdf’)[rand(0,3)];
Т.е. ты считаешь, что (независимо от «задумки» разраба) в будущем конфигурировать этот список не понадобится? Ок.
Источник
746 votes
5 answers


Get the solution ↓↓↓
I am getting an error:
Fatal error: Constant expression contains invalid operations in
config.php on line 214
That line was:
protected static $dbname = 'mydb_'.$appdata['id'];
Whether I did any mistakes in quotes? Or somewhere else?
My search for the error message only showed a different source cause (a dynamic default value in a function definition).
2021-11-6
Write your answer
868
votes


Answer
Solution:
From the official Php documentation :
Like any other PHP static variable, static properties may only be initialized using a literal or constant before PHP 5.6; expressions are not allowed. In PHP 5.6 and later, the same rules apply as const expressions: some limited expressions are possible, provided they can be evaluated at compile time.
So you cannot initialize a static variable with another variable. Replace$appdata['id'] with a constant string or remove thestatic attribute.
This is because all static declarations are resolved in compile-time, when the content of other variables is not known (see this other page of official doc).
688
votes


Answer
Solution:
Unless you mess with reflection, the only way I can think of to have a static private/protected class property with a dynamically generated value is to calculate it outside the class:
class Foo {
protected static $dbname = DBNAME;
public static function debug() {
return Foo::$dbname;
}
}
$appdata = array(
'id' => 31416,
);
define('DBNAME', 'mydb_'.$appdata['id']);
var_dump(Foo::debug());
In your precise use case, however, it’s possible that there’s simply no good reason for the property to be static. In that case, it’s as straightforward as using the constructor:
class Foo {
protected $dbname;
public function __construct($appdata){
$this->dbname = 'mydb_'.$appdata['id'];
}
public function debug() {
return $this->dbname;
}
}
$appdata = array(
'id' => 31416,
);
$foo = new Foo($appdata);
var_dump($foo->debug());
820
votes


Answer
Solution:
This is because a static variable contains a constant value in it. But in your case:
protected static $dbname = 'mydb_'.$appdata['id'];
$appdata['id'] is dynamic that can change its value during the execution. That’s why the error is showing.
97
votes


Answer
Solution:
I had this error and my fix was to not declare a date within a class property array
public static $config_array = array(
'start_date' => date('Y-m-d H:i:s') // No can do
);
444
votes


Answer
Solution:
For your information:-
I got the same error by using some characters in a constant expressions.
public static $dbPassword="[email protected]||sR";
This is what caused the error and I removed this || which is the logical OR operator characters from the string and it worked.
Share solution ↓
Additional Information:
Date the issue was resolved:
2021-11-6
Link To Source
Link To Answer
People are also looking for solutions of the problem: port 80 in use by «unable to open process» with pid 4!
Didn’t find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
I am getting an error:
Fatal error: Constant expression contains invalid operations in config.php on line 214
That line was:
protected static $dbname = 'mydb_'.$appdata['id'];
Whether I did any mistakes in quotes? Or somewhere else?
My search for the error message only showed a different source cause (a dynamic default value in a function definition).
Nov 8, 2020
in PHP
by
• 37,510 points
•
12,073 views
1 answer to this question.
Hello @kartik,
This is because a static variable contains a constant value in it. But in your case:
protected static $dbname = 'mydb_'.$appdata['id'];
$appdata[‘id’] is dynamic that can change its value during the execution. That’s why the error is showing.
Hope it helps!!
answered
Nov 8, 2020
by
Niroj
• 82,840 points
Related Questions In PHP
- All categories
-
ChatGPT
(4) -
Apache Kafka
(84) -
Apache Spark
(596) -
Azure
(131) -
Big Data Hadoop
(1,907) -
Blockchain
(1,673) -
C#
(141) -
C++
(271) -
Career Counselling
(1,060) -
Cloud Computing
(3,446) -
Cyber Security & Ethical Hacking
(147) -
Data Analytics
(1,266) -
Database
(855) -
Data Science
(75) -
DevOps & Agile
(3,575) -
Digital Marketing
(111) -
Events & Trending Topics
(28) -
IoT (Internet of Things)
(387) -
Java
(1,247) -
Kotlin
(8) -
Linux Administration
(389) -
Machine Learning
(337) -
MicroStrategy
(6) -
PMP
(423) -
Power BI
(516) -
Python
(3,188) -
RPA
(650) -
SalesForce
(92) -
Selenium
(1,569) -
Software Testing
(56) -
Tableau
(608) -
Talend
(73) -
TypeSript
(124) -
Web Development
(3,002) -
Ask us Anything!
(66) -
Others
(1,929) -
Mobile Development
(263)
Subscribe to our Newsletter, and get personalized recommendations.
Already have an account? Sign in.
Вступление
Классы и объекты используются, чтобы сделать ваш код более эффективным и менее повторяющимся, группируя подобные задачи.
Класс используется для определения действий и структуры данных, используемых для создания объектов. Затем объекты создаются с использованием этой предопределенной структуры.
Синтаксис
-
class <ClassName> [ extends <ParentClassName> ] [ implements <Interface1> [, <Interface2>, ... ] { }// Объявление класса -
interface <InterfaceName> [ extends <ParentInterface1> [, <ParentInterface2>, ...] ] { }// Объявление интерфейса -
use <Trait1> [, <Trait2>, ...]; // Использовать черты -
[ public | protected | private ] [ static ] $<varName>;// Объявление атрибута -
const <CONST_NAME>;// Декларация константы -
[ public | protected | private ] [ static ] function <methodName>([args...]) { }// Объявление метода
замечания
Классы и компоненты интерфейса
Классы могут иметь свойства, константы и методы.
- Свойства содержат переменные в объеме объекта. Они могут быть инициализированы при объявлении, но только если они содержат примитивное значение.
- Константы должны быть инициализированы в декларации и могут содержать только примитивное значение. Константные значения фиксируются во время компиляции и не могут быть назначены во время выполнения.
- Методы должны иметь тело, даже пустое, если метод не объявлен абстрактным.
class Foo {
private $foo = 'foo'; // OK
private $baz = array(); // OK
private $bar = new Bar(); // Error!
}
Интерфейсы не могут иметь свойств, но могут иметь константы и методы.
- Константы интерфейса должны быть инициализированы при объявлении и могут содержать только примитивное значение. Константные значения фиксируются во время компиляции и не могут быть назначены во время выполнения.
- Методы интерфейса не имеют тела.
interface FooBar {
const FOO_VALUE = 'bla';
public function doAnything();
}
Интерфейсы
Вступление
Интерфейсы — это определения общедоступных классов API, которые должны реализовывать, чтобы удовлетворить интерфейс. Они работают как «контракты», указывая, что делает набор подклассов, но не то, как они это делают.
Определение интерфейса очень похоже на определение класса, изменение class ключевого слова для interface :
interface Foo {
}
Интерфейсы могут содержать методы и / или константы, но не атрибуты. Интерфейсные константы имеют те же ограничения, что и константы класса. Методы интерфейса неявно абстрактны:
interface Foo {
const BAR = 'BAR';
public function doSomething($param1, $param2);
}
Примечание. Интерфейсы не должны объявлять конструкторы или деструкторы, поскольку это детали реализации на уровне класса.
реализация
Любой класс , который должен реализовать интерфейс должен сделать это , используя implements ключевое слово. Для этого класс должен обеспечить реализацию для каждого метода, объявленного в интерфейсе, в соответствии с той же сигнатурой.
Один класс может одновременно реализовать более одного интерфейса.
interface Foo {
public function doSomething($param1, $param2);
}
interface Bar {
public function doAnotherThing($param1);
}
class Baz implements Foo, Bar {
public function doSomething($param1, $param2) {
// ...
}
public function doAnotherThing($param1) {
// ...
}
}
Когда абстрактные классы реализуют интерфейсы, им не нужно реализовывать все методы. Любой метод, не реализованный в базовом классе, должен быть реализован конкретным классом, который его расширяет:
abstract class AbstractBaz implements Foo, Bar {
// Partial implementation of the required interface...
public function doSomething($param1, $param2) {
// ...
}
}
class Baz extends AbstractBaz {
public function doAnotherThing($param1) {
// ...
}
}
Обратите внимание, что реализация интерфейса является наследуемой характеристикой. При расширении класса, реализующего интерфейс, вам не нужно его повторять в конкретном классе, потому что он неявный.
Примечание. До PHP 5.3.9 класс не смог реализовать два интерфейса, которые указали метод с тем же именем, поскольку это вызовет неоднозначность. Более поздние версии PHP допускают это, если дублирующие методы имеют одну и ту же подпись [1] .
наследование
Подобно классам, можно установить отношения наследования между интерфейсами, используя одно и то же ключевое слово extends . Основное различие заключается в том, что для интерфейсов допускается множественное наследование:
interface Foo {
}
interface Bar {
}
interface Baz extends Foo, Bar {
}
Примеры
В приведенном ниже примере у нас есть простой пример интерфейса для транспортного средства. Транспортные средства могут двигаться вперед и назад.
interface VehicleInterface {
public function forward();
public function reverse();
...
}
class Bike implements VehicleInterface {
public function forward() {
$this->pedal();
}
public function reverse() {
$this->backwardSteps();
}
protected function pedal() {
...
}
protected function backwardSteps() {
...
}
...
}
class Car implements VehicleInterface {
protected $gear = 'N';
public function forward() {
$this->setGear(1);
$this->pushPedal();
}
public function reverse() {
$this->setGear('R');
$this->pushPedal();
}
protected function setGear($gear) {
$this->gear = $gear;
}
protected function pushPedal() {
...
}
...
}
Затем мы создаем два класса, которые реализуют интерфейс: Bike and Car. Велосипед и автомобиль внутри очень разные, но оба являются транспортными средствами и должны реализовывать те же общедоступные методы, которые предоставляет VehicleInterface.
Typehinting позволяет методам и функциям запрашивать интерфейсы. Предположим, что у нас есть класс гаража, который содержит автомобили всех видов.
class ParkingGarage {
protected $vehicles = [];
public function addVehicle(VehicleInterface $vehicle) {
$this->vehicles[] = $vehicle;
}
}
Потому что addVehicle требует $vehicle типа VehicleInterface — не конкретная реализация — мы можем вводить как велосипеды, так и автомобили, которые ParkingGarage может манипулировать и использовать.
Константы классов
Константы класса предоставляют механизм для хранения фиксированных значений в программе. То есть они предоставляют способ дать имя (и связанную проверку времени компиляции) до значения, такого как 3.14 или "Apple" . Константы класса могут быть определены только с помощью ключевого слова const — функция определения не может использоваться в этом контексте.
В качестве примера может быть удобно иметь сокращенное представление для значения π во всей программе. Класс со значениями const предоставляет простой способ для хранения таких значений.
class MathValues {
const PI = M_PI;
const PHI = 1.61803;
}
$area = MathValues::PI * $radius * $radius;
К константам класса можно получить доступ, используя оператор двойной толчки (так называемый оператор разрешения области) в классе, подобно статическим переменным. Однако, в отличие от статических переменных, константы класса имеют фиксированные значения во время компиляции и не могут быть переназначены (например, MathValues::PI = 7 приведет к фатальной ошибке).
Константы классов также полезны для определения вещей внутри класса, которые могут потребоваться позже изменить (но не изменяются достаточно часто, чтобы гарантировать хранение, скажем, базы данных). Мы можем ссылаться на это внутренне , используя self области действия resolutor (который работает в обоих инстансы и статических реализаций)
class Labor {
/** How long, in hours, does it take to build the item? */
const LABOR_UNITS = 0.26;
/** How much are we paying employees per hour? */
const LABOR_COST = 12.75;
public function getLaborCost($number_units) {
return (self::LABOR_UNITS * self::LABOR_COST) * $number_units;
}
}
Константы класса могут содержать только скалярные значения в версиях <5.6
Начиная с PHP 5.6 мы можем использовать выражения с константами, то есть математические утверждения и строки с конкатенацией являются допустимыми константами
class Labor {
/** How much are we paying employees per hour? Hourly wages * hours taken to make */
const LABOR_COSTS = 12.75 * 0.26;
public function getLaborCost($number_units) {
return self::LABOR_COSTS * $number_units;
}
}
Начиная с PHP 7.0, константы, объявленные с помощью define теперь могут содержать массивы.
define("BAZ", array('baz'));
Константы класса полезны не только для хранения математических понятий. Например, при приготовлении пирога может быть удобно иметь один класс Pie способный принимать различные виды фруктов.
class Pie {
protected $fruit;
public function __construct($fruit) {
$this->fruit = $fruit;
}
}
Затем мы можем использовать класс Pie
$pie = new Pie("strawberry");
Проблема, возникающая здесь, заключается в том, что при создании класса Pie никаких указаний относительно допустимых значений не предоставляется. Например, при создании пирога «мальковки» это может быть написано с ошибкой «boisenberry». Кроме того, мы не можем поддерживать сливочный пирог. Вместо этого было бы полезно иметь список приемлемых типов фруктов, которые уже были определены где-то, было бы целесообразно искать их. Скажите класс под названием Fruit :
class Fruit {
const APPLE = "apple";
const STRAWBERRY = "strawberry";
const BOYSENBERRY = "boysenberry";
}
$pie = new Pie(Fruit::STRAWBERRY);
Перечисление допустимых значений в качестве констант класса дает ценный совет относительно приемлемых значений, которые принимает метод. Это также гарантирует, что орфографические ошибки не могут пройти мимо компилятора. В то время как new Pie('aple') и new Pie('apple') приемлемы для компилятора, new Pie(Fruit::APLE) приведет к ошибке компилятора.
Наконец, использование констант класса означает, что фактическое значение константы может быть изменено в одном месте, а любой код с использованием константы автоматически имеет последствия модификации.
Хотя наиболее распространенным методом доступа к константе класса является MyClass::CONSTANT_NAME , к нему также можно получить доступ:
echo MyClass::CONSTANT;
$classname = "MyClass";
echo $classname::CONSTANT; // As of PHP 5.3.0
Константы класса в PHP условно называются все в верхнем регистре с подчеркиваниями как разделители слов, хотя любое допустимое имя метки может использоваться как имя константы класса.
Начиная с PHP 7.1, теперь константы класса могут быть определены с различной видимостью из общедоступной области по умолчанию. Это означает, что теперь можно определить как защищенные, так и частные константы, чтобы предотвратить ненужные утечки констант класса в общедоступную область видимости (см. « Метод и видимость свойств» ). Например:
class Something {
const PUBLIC_CONST_A = 1;
public const PUBLIC_CONST_B = 2;
protected const PROTECTED_CONST = 3;
private const PRIVATE_CONST = 4;
}
определить vs константы класса
Хотя это действительная конструкция:
function bar() { return 2; };
define('BAR', bar());
Если вы попытаетесь сделать то же самое с константами класса, вы получите сообщение об ошибке:
function bar() { return 2; };
class Foo {
const BAR = bar(); // Error: Constant expression contains invalid operations
}
Но вы можете сделать:
function bar() { return 2; };
define('BAR', bar());
class Foo {
const BAR = BAR; // OK
}
Для получения дополнительной информации см. Константы в руководстве .
Использование :: class для извлечения имени класса
PHP 5.5 ввел ::class синтаксис , чтобы получить полное имя класса, принимая область пространства имен и use заявление во внимание.
namespace foo;
use barBar;
echo json_encode(Bar::class); // "bar\Bar"
echo json_encode(Foo::class); // "foo\Foo"
echo json_encode(Foo::class); // "Foo"
Вышеупомянутое работает, даже если классы даже не определены (т. Е. Этот фрагмент кода работает в одиночку).
Этот синтаксис полезен для функций, для которых требуется имя класса. Например, он может использоваться с class_exists для проверки класса. Ошибки не будут генерироваться независимо от возвращаемого значения в этом фрагменте:
class_exists(ThisClassWillNeverBeLoaded::class, false);
Поздняя статическая привязка
В PHP 5.3+ и выше вы можете использовать позднюю статическую привязку для управления классом, из которого вызывается статическое свойство или метод. Он был добавлен для преодоления проблемы, присущей разрешателю self:: scope. Возьмите следующий код
class Horse {
public static function whatToSay() {
echo 'Neigh!';
}
public static function speak() {
self::whatToSay();
}
}
class MrEd extends Horse {
public static function whatToSay() {
echo 'Hello Wilbur!';
}
}
Можно ожидать , что MrEd класс будет переопределить родительский whatToSay() функцию. Но когда мы запускаем это, мы получаем что-то неожиданное
Horse::speak(); // Neigh!
MrEd::speak(); // Neigh!
Проблема в том, что self::whatToSay(); может относиться только к классу Horse , то есть он не подчиняется MrEd . Если мы перейдем к разрешению static:: scope, у нас нет этой проблемы. Этот новый метод сообщает классу подчиняться экземпляру, вызывающему его. Таким образом, мы получаем наследство, которое мы ожидаем
class Horse {
public static function whatToSay() {
echo 'Neigh!';
}
public static function speak() {
static::whatToSay(); // Late Static Binding
}
}
Horse::speak(); // Neigh!
MrEd::speak(); // Hello Wilbur!
Абстрактные классы
Абстрактный класс — это класс, который не может быть создан. Абстрактные классы могут определять абстрактные методы, которые являются методами без какого-либо тела, а только определение:
abstract class MyAbstractClass {
abstract public function doSomething($a, $b);
}
Абстрактные классы должны быть расширены дочерним классом, который затем может обеспечить реализацию этих абстрактных методов.
Основная цель такого класса — предоставить своего рода шаблон, который позволяет дочерним классам наследовать, «заставляя» структуру, к которой она привязана. Давайте подробнее рассмотрим этот пример:
В этом примере мы реализуем интерфейс Worker . Сначала мы определяем интерфейс:
interface Worker {
public function run();
}
Чтобы облегчить разработку дальнейших реализаций Worker, мы создадим абстрактный класс работника, который уже предоставляет метод run() из интерфейса, но указывает некоторые абстрактные методы, которые должны быть заполнены любым дочерним классом:
abstract class AbstractWorker implements Worker {
protected $pdo;
protected $logger;
public function __construct(PDO $pdo, Logger $logger) {
$this->pdo = $pdo;
$this->logger = $logger;
}
public function run() {
try {
$this->setMemoryLimit($this->getMemoryLimit());
$this->logger->log("Preparing main");
$this->prepareMain();
$this->logger->log("Executing main");
$this->main();
} catch (Throwable $e) {
// Catch and rethrow all errors so they can be logged by the worker
$this->logger->log("Worker failed with exception: {$e->getMessage()}");
throw $e;
}
}
private function setMemoryLimit($memoryLimit) {
ini_set('memory_limit', $memoryLimit);
$this->logger->log("Set memory limit to $memoryLimit");
}
abstract protected function getMemoryLimit();
abstract protected function prepareMain();
abstract protected function main();
}
Прежде всего, мы предоставили абстрактный метод getMemoryLimit() . Любой класс, простирающийся от AbstractWorker должен предоставить этот метод и вернуть свой предел памяти. Затем AbstractWorker устанавливает ограничение на память и записывает его в журнал.
Во-вторых, AbstractWorker вызывает prepareMain() и main() после регистрации, что они были вызваны.
Наконец, все эти вызовы методов были сгруппированы в блок try catch . Поэтому, если какой-либо из абстрактных методов, определяемых дочерним классом, генерирует исключение, мы поймаем это исключение, запишем его в журнал и перестроим. Это не позволяет всем дочерним классам реализовать это самостоятельно.
Теперь давайте определим дочерний класс, который простирается от AbstractWorker :
class TranscactionProcessorWorker extends AbstractWorker {
private $transactions;
protected function getMemoryLimit() {
return "512M";
}
protected function prepareMain() {
$stmt = $this->pdo->query("SELECT * FROM transactions WHERE processed = 0 LIMIT 500");
$stmt->execute();
$this->transactions = $stmt->fetchAll();
}
protected function main() {
foreach ($this->transactions as $transaction) {
// Could throw some PDO or MYSQL exception, but that is handled by the AbstractWorker
$stmt = $this->pdo->query("UPDATE transactions SET processed = 1 WHERE id = {$transaction['id']} LIMIT 1");
$stmt->execute();
}
}
}
Как вы можете видеть, TransactionProcessorWorker был довольно прост в реализации, поскольку нам нужно было указать ограничение на память и беспокоиться о действительных действиях, которые ему нужно выполнить. Обработка TransactionProcessorWorker требуется в TransactionProcessorWorker потому что это обрабатывается в AbsractWorker .
Важная заметка
При наследовании от абстрактного класса все методы, помеченные как абстрактные в объявлении класса родителя, должны быть определены дочерним элементом (или сам ребенок также должен быть отмечен как абстрактный); кроме того, эти методы должны быть определены с той же (или менее ограниченной) видимостью. Например, если абстрактный метод определяется как защищенный, реализация функции должна быть определена как защищенная или общедоступная, но не закрытая.
Взято из документации PHP для абстракции класса .
Если вы не определяете родительские методы абстрактных классов в дочернем классе, вы будете подвергнуты Fatal PHP Error, как показано ниже.
Неустранимая ошибка: класс X содержит 1 абстрактный метод и поэтому должен быть объявлен абстрактным или реализовать оставшиеся методы (X :: x) в
Распространение имен и автозагрузка
Технически, автозагрузка работает, выполняя обратный вызов, когда требуется класс PHP, но не найден. Такие обратные вызовы обычно пытаются загрузить эти классы.
Как правило, автозагрузку можно понимать как попытку загрузить файлы PHP (особенно файлы классов PHP, где исходный PHP-файл предназначен для определенного класса) из соответствующих путей в соответствии с полным именем класса (FQN), когда класс необходим ,
Предположим, что у нас есть эти классы:
Файл класса для applicationcontrollersBase :
<?php
namespace applicationcontrollers { class Base {...} }
Файл класса для applicationcontrollersControl :
<?php
namespace applicationcontrollers { class Control {...} }
Файл класса для applicationmodelsPage :
<?php
namespace applicationmodels { class Page {...} }
В исходной папке эти классы должны быть помещены на пути как их FQN соответственно:
- Папка источника
-
applications-
controllers-
Base.php -
Control.php
-
-
models-
Page.php
-
-
-
Такой подход позволяет программно разрешать путь к файлу класса в соответствии с FQN, используя эту функцию:
function getClassPath(string $sourceFolder, string $className, string $extension = ".php") {
return $sourceFolder . "/" . str_replace("\", "/", $className) . $extension; // note that "/" works as a directory separator even on Windows
}
Функция spl_autoload_register позволяет нам загружать класс при необходимости с помощью пользовательской функции:
const SOURCE_FOLDER = __DIR__ . "/src";
spl_autoload_register(function (string $className) {
$file = getClassPath(SOURCE_FOLDER, $className);
if (is_readable($file)) require_once $file;
});
Эта функция может быть дополнительно расширена для использования резервных методов загрузки:
const SOURCE_FOLDERS = [__DIR__ . "/src", "/root/src"]);
spl_autoload_register(function (string $className) {
foreach(SOURCE_FOLDERS as $folder) {
$extensions = [
// do we have src/Foo/Bar.php5_int64?
".php" . PHP_MAJOR_VERSION . "_int" . (PHP_INT_SIZE * 8),
// do we have src/Foo/Bar.php7?
".php" . PHP_MAJOR_VERSION,
// do we have src/Foo/Bar.php_int64?
".php" . "_int" . (PHP_INT_SIZE * 8),
// do we have src/Foo/Bar.phps?
".phps"
// do we have src/Foo/Bar.php?
".php"
];
foreach($extensions as $ext) {
$path = getClassPath($folder, $className, $extension);
if(is_readable($path)) return $path;
}
}
});
Обратите внимание: PHP не пытается загружать классы всякий раз, когда загружается файл, который использует этот класс. Он может быть загружен в середине скрипта или даже в функциях выключения. Это одна из причин, почему разработчикам, особенно тем, кто использует автозагрузку, следует избегать замены исполняемых исходных файлов во время выполнения, особенно в файлах phar.
Динамическое связывание
Динамическое связывание, также называемое переопределением метода, является примером полиморфизма времени выполнения, который возникает, когда несколько классов содержат разные реализации одного и того же метода, но объект, к которому будет вызван метод, неизвестен до времени выполнения .
Это полезно, если определенное условие определяет, какой класс будет использоваться для выполнения действия, где действие называется одинаковым в обоих классах.
interface Animal {
public function makeNoise();
}
class Cat implements Animal {
public function makeNoise
{
$this->meow();
}
...
}
class Dog implements Animal {
public function makeNoise {
$this->bark();
}
...
}
class Person {
const CAT = 'cat';
const DOG = 'dog';
private $petPreference;
private $pet;
public function isCatLover(): bool {
return $this->petPreference == self::CAT;
}
public function isDogLover(): bool {
return $this->petPreference == self::DOG;
}
public function setPet(Animal $pet) {
$this->pet = $pet;
}
public function getPet(): Animal {
return $this->pet;
}
}
if($person->isCatLover()) {
$person->setPet(new Cat());
} else if($person->isDogLover()) {
$person->setPet(new Dog());
}
$person->getPet()->makeNoise();
В приведенном выше примере класс Animal ( Dog|Cat ), который будет makeNoise , неизвестен до времени выполнения в зависимости от свойства в классе User .
Видимость метода и свойств
Существует три типа видимости, которые можно применять к методам (функции класса / объекта ) и свойствам ( переменные класса / объекта ) в классе, которые обеспечивают контроль доступа для метода или свойства, к которому они применяются.
Вы можете подробно ознакомиться с ними в документации PHP для видимости ООП .
общественного
Объявление метода или свойства как public позволяет доступ к способу или свойствам посредством:
- Класс, который его объявил.
- Классы, которые расширяют объявленный класс.
- Любые внешние объекты, классы или код вне иерархии классов.
Примером такого public доступа будет:
class MyClass {
// Property
public $myProperty = 'test';
// Method
public function myMethod() {
return $this->myProperty;
}
}
$obj = new MyClass();
echo $obj->myMethod();
// Out: test
echo $obj->myProperty;
// Out: test
защищенный
Объявление метода или свойства как protected позволяет доступ к способу или свойствам посредством:
- Класс, который его объявил.
- Классы, которые расширяют объявленный класс.
Это не позволяет внешним объектам, классам или кодам за пределами иерархии классов обращаться к этим методам или свойствам. Если что-то, использующее этот метод / свойство, не имеет к нему доступа, оно не будет доступно, и будет вызвана ошибка. Доступ к нему имеют только экземпляры объявленного себя (или подклассы).
Примером этого protected доступа будет:
class MyClass {
protected $myProperty = 'test';
protected function myMethod() {
return $this->myProperty;
}
}
class MySubClass extends MyClass {
public function run() {
echo $this->myMethod();
}
}
$obj = new MySubClass();
$obj->run(); // This will call MyClass::myMethod();
// Out: test
$obj->myMethod(); // This will fail.
// Out: Fatal error: Call to protected method MyClass::myMethod() from context ''
В приведенном выше примере отмечается, что вы можете получить доступ только к protected элементам внутри своей собственной области. По существу: «В доме есть доступ только из дома».
Частный
Объявление метода или свойства как private позволяет доступ к способу или свойствам посредством:
- Класс, который объявил это только (не подклассы).
private метод или свойство только видимы и доступны внутри класса, который его создал.
Обратите внимание, что объекты того же типа будут иметь доступ к каждому другому частному и защищенному членам, даже если они не совпадают с экземплярами.
class MyClass {
private $myProperty = 'test';
private function myPrivateMethod() {
return $this->myProperty;
}
public function myPublicMethod() {
return $this->myPrivateMethod();
}
public function modifyPrivatePropertyOf(MyClass $anotherInstance) {
$anotherInstance->myProperty = "new value";
}
}
class MySubClass extends MyClass {
public function run() {
echo $this->myPublicMethod();
}
public function runWithPrivate() {
echo $this->myPrivateMethod();
}
}
$obj = new MySubClass();
$newObj = new MySubClass();
// This will call MyClass::myPublicMethod(), which will then call
// MyClass::myPrivateMethod();
$obj->run();
// Out: test
$obj->modifyPrivatePropertyOf($newObj);
$newObj->run();
// Out: new value
echo $obj->myPrivateMethod(); // This will fail.
// Out: Fatal error: Call to private method MyClass::myPrivateMethod() from context ''
echo $obj->runWithPrivate(); // This will also fail.
// Out: Fatal error: Call to private method MyClass::myPrivateMethod() from context 'MySubClass'
Как уже отмечалось, вы можете получить доступ только к private методу / свойству из его определенного класса.
Вызов родительского конструктора при создании экземпляра дочернего элемента
Общей ошибкой дочерних классов является то, что если ваш родитель и ребенок содержат конструктор ( __construct() ), будет запускаться только конструктор дочернего класса . Могут быть случаи, когда вам нужно запустить родительский __construct() из его дочернего элемента. Если вам нужно это сделать, вам нужно будет использовать разрешение parent:: scope:
parent::__construct();
Теперь использование этого в реальной ситуации будет выглядеть примерно так:
class Foo {
function __construct($args) {
echo 'parent';
}
}
class Bar extends Foo {
function __construct($args) {
parent::__construct($args);
}
}
Вышеупомянутый __construct() будет запускать родительский __construct() результате которого выполняется echo .
Конечное ключевое слово
Def: Final Keyword не позволяет дочерним классам переопределять метод, префикс определения с помощью final. Если сам класс определяется окончательным, то он не может быть расширен
Конечный метод
class BaseClass {
public function test() {
echo "BaseClass::test() calledn";
}
final public function moreTesting() {
echo "BaseClass::moreTesting() calledn";
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo "ChildClass::moreTesting() calledn";
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
Конечный класс:
final class BaseClass {
public function test() {
echo "BaseClass::test() calledn";
}
// Here it doesn't matter if you specify the function as final or not
final public function moreTesting() {
echo "BaseClass::moreTesting() calledn";
}
}
class ChildClass extends BaseClass {
}
// Results in Fatal error: Class ChildClass may not inherit from final class (BaseClass)
Конечные константы. В отличие от Java, ключевое слово final не используется для констант класса в PHP. Вместо этого используйте ключевое слово const .
Почему я должен использовать final ?
- Предотвращение массивной цепи наследования гибели
- Поощрение композиции
- Заставить разработчика задуматься о пользовательском публичном API
- Принудите разработчика к сокращению открытого API объекта
-
finalкласс всегда можно сделать расширяемым -
extendsинкапсуляцию разрывов - Вам не нужна такая гибкость
- Вы можете изменить код
Когда следует избегать final : окончательные занятия работают эффективно только при следующих предположениях:
- Существует абстракция (интерфейс), которую конечный класс реализует
- Весь публичный API конечного класса является частью этого интерфейса
$ this, self и static plus singleton
Используйте
$thisдля обозначения текущего объекта. Используйтеselfдля обозначения текущего класса. Другими словами, используйте$this->memberдля нестатических членов, используйтеself::$memberдля статических членов.
В приведенном ниже примере sayHello() и sayGoodbye() используют self и $this разницу можно наблюдать здесь.
class Person {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function getTitle() {
return $this->getName()." the person";
}
public function sayHello() {
echo "Hello, I'm ".$this->getTitle()."<br/>";
}
public function sayGoodbye() {
echo "Goodbye from ".self::getTitle()."<br/>";
}
}
class Geek extends Person {
public function __construct($name) {
parent::__construct($name);
}
public function getTitle() {
return $this->getName()." the geek";
}
}
$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();
static ссылается на любой класс в иерархии, которую вы назвали методом on. Это позволяет лучше использовать статические свойства класса при наследовании классов.
Рассмотрим следующий код:
class Car {
protected static $brand = 'unknown';
public static function brand() {
return self::$brand."n";
}
}
class Mercedes extends Car {
protected static $brand = 'Mercedes';
}
class BMW extends Car {
protected static $brand = 'BMW';
}
echo (new Car)->brand();
echo (new BMW)->brand();
echo (new Mercedes)->brand();
Это не приводит к желаемому результату:
неизвестный
неизвестный
неизвестный
Это потому, что self относится к классу Car всякий раз, когда вызывается метод brand() .
Чтобы обратиться к правильному классу, вам нужно использовать static :
class Car {
protected static $brand = 'unknown';
public static function brand() {
return static::$brand."n";
}
}
class Mercedes extends Car {
protected static $brand = 'Mercedes';
}
class BMW extends Car {
protected static $brand = 'BMW';
}
echo (new Car)->brand();
echo (new BMW)->brand();
echo (new Mercedes)->brand();
Это дает желаемый результат:
неизвестный
БМВ
Mercedes
См. Также Поздняя статическая привязка
Синглтон
Если у вас есть объект, который стоит создавать или представляет соединение с каким-либо внешним ресурсом, который вы хотите повторно использовать, то есть соединение с базой данных, в котором нет пула соединений или сокета в какой-либо другой системе, вы можете использовать static и self ключевые слова в класс, чтобы сделать его одиночным. Есть сильные мнения о том, следует ли использовать одноэлементный шаблон или не использовать, но он действительно использует его.
class Singleton {
private static $instance = null;
public static function getInstance(){
if(!isset(self::$instance)){
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
// Do constructor stuff
}
}
Как вы можете видеть в примере кода, мы определяем приватное статическое свойство $instance для хранения ссылки на объект. Поскольку это статично, эта ссылка используется для всех объектов этого типа.
Метод getInstance() использует метод, известный как ленивый экземпляр, чтобы отложить создание объекта до последнего возможного момента, поскольку вы не хотите, чтобы в памяти не использовались неиспользуемые объекты, которые никогда не предназначались для использования. Это также экономит время, и процессор на загрузке страницы не загружает больше объектов, чем необходимо. Метод проверяет, установлен ли объект, создавая его, если нет, и возвращает его. Это гарантирует, что только один объект такого типа будет создан.
Мы также устанавливаем конструктор как частный, чтобы гарантировать, что никто не создает его с new ключевым словом извне. Если вам нужно наследовать от этого класса, просто измените private ключевые слова на protected .
Чтобы использовать этот объект, вы просто пишете следующее:
$singleton = Singleton::getInstance();
Теперь я умоляю вас использовать инъекцию зависимостей, где вы можете, и стремиться к слабосвязанным объектам, но иногда это просто неразумно, и одноэлементный шаблон может быть полезен.
Автозагрузка
Никто не хочет require или include каждый раз, когда используется класс или наследование. Поскольку это может быть болезненным и легко забыть, PHP предлагает так называемую автозагрузку. Если вы уже используете Composer, прочитайте об автозагрузке с помощью Composer .
Что такое автозагрузка?
Название в основном говорит все. Вам не нужно , чтобы получить файл , когда запрашиваемое класс хранится в, но PHP автоматически матически нагрузки все.
Как я могу сделать это в базовом PHP без стороннего кода?
Существует функция __autoload , но считается, что лучше использовать spl_autoload_register . Эти функции будут рассмотрены PHP каждый раз, когда класс не определен в данном пространстве. Поэтому добавление автозагрузки в существующий проект не представляет проблемы, поскольку определенные классы (через require ie) будут работать, как раньше. Для обеспечения точности в следующих примерах будут использоваться анонимные функции, если вы используете PHP <5.3, вы можете определить функцию и передать ее имя в качестве аргумента spl_autoload_register .
Примеры
spl_autoload_register(function ($className) {
$path = sprintf('%s.php', $className);
if (file_exists($path)) {
include $path;
} else {
// file not found
}
});
Вышеприведенный код просто пытается включить имя файла с именем класса и добавленным расширением «.php», используя sprintf . Если FooBar необходимо загрузить, он выглядит, если FooBar.php существует, и если он включает его.
Конечно, это можно расширить, чтобы соответствовать индивидуальным потребностям проекта. Если _ внутри имени класса используется для группировки, например User_Post и User_Image оба относятся к User , оба класса могут храниться в папке «Пользователь», например:
spl_autoload_register(function ($className) {
// replace _ by / or (depending on OS)
$path = sprintf('%s.php', str_replace('_', DIRECTORY_SEPARATOR, $className) );
if (file_exists($path)) {
include $path;
} else {
// file not found
}
});
Класс User_Post теперь будет загружен из «User / Post.php» и т. Д.
spl_autoload_register может быть адаптирован к различным потребностям. Все ваши файлы с классами называются «class.CLASSNAME.php»? Нет проблем. Различная вложенность ( User_Post_Content => «Пользователь / Сообщение / Содержание.php»)? Нет проблем.
Если вам нужен более сложный механизм автозагрузки — и вы не хотите включать Composer, вы можете работать без добавления сторонних библиотек.
spl_autoload_register(function ($className) {
$path = sprintf('%1$s%2$s%3$s.php',
// %1$s: get absolute path
realpath(dirname(__FILE__)),
// %2$s: / or (depending on OS)
DIRECTORY_SEPARATOR,
// %3$s: don't wory about caps or not when creating the files
strtolower(
// replace _ by / or (depending on OS)
str_replace('_', DIRECTORY_SEPARATOR, $className)
)
);
if (file_exists($path)) {
include $path;
} else {
throw new Exception(
sprintf('Class with name %1$s not found. Looked in %2$s.',
$className,
$path
)
);
}
});
Используя автозагрузчики, подобные этому, вы можете с радостью написать такой код:
require_once './autoload.php'; // where spl_autoload_register is defined
$foo = new Foo_Bar(new Hello_World());
Использование классов:
class Foo_Bar extends Foo {}
class Hello_World implements Demo_Classes {}
Эти примеры будут включать классы из foo/bar.php , foo.php , hello/world.php и demo/classes.php .
Анонимные классы
Анонимные классы были введены в PHP 7, чтобы можно было легко создавать быстрые одноразовые объекты. Они могут принимать аргументы конструктора, расширять другие классы, реализовывать интерфейсы и использовать черты так же, как обычные классы.
В своей основной форме анонимный класс выглядит следующим образом:
new class("constructor argument") {
public function __construct($param) {
var_dump($param);
}
}; // string(20) "constructor argument"
Вложение анонимного класса внутри другого класса не дает ему доступа к закрытым или защищенным методам или свойствам этого внешнего класса. Доступ к защищенным методам и свойствам внешнего класса может быть получен путем расширения внешнего класса из анонимного класса. Доступ к приватным свойствам внешнего класса можно получить, передав их конструктору анонимного класса.
Например:
class Outer {
private $prop = 1;
protected $prop2 = 2;
protected function func1() {
return 3;
}
public function func2() {
// passing through the private $this->prop property
return new class($this->prop) extends Outer {
private $prop3;
public function __construct($prop) {
$this->prop3 = $prop;
}
public function func3() {
// accessing the protected property Outer::$prop2
// accessing the protected method Outer::func1()
// accessing the local property self::$prop3 that was private from Outer::$prop
return $this->prop2 + $this->func1() + $this->prop3;
}
};
}
}
echo (new Outer)->func2()->func3(); // 6
Определение базового класса
Объект в PHP содержит переменные и функции. Объекты обычно принадлежат классу, который определяет переменные и функции, которые будут содержать все объекты этого класса.
Синтаксис для определения класса:
class Shape {
public $sides = 0;
public function description() {
return "A shape with $this->sides sides.";
}
}
Как только класс определен, вы можете создать экземпляр, используя:
$myShape = new Shape();
Доступ к переменным и функциям объекта осуществляется следующим образом:
$myShape = new Shape();
$myShape->sides = 6;
print $myShape->description(); // "A shape with 6 sides"
Конструктор
Классы могут определять специальный __construct() , который выполняется как часть создания объекта. Это часто используется для указания начальных значений объекта:
class Shape {
public $sides = 0;
public function __construct($sides) {
$this->sides = $sides;
}
public function description() {
return "A shape with $this->sides sides.";
}
}
$myShape = new Shape(6);
print $myShape->description(); // A shape with 6 sides
Расширение другого класса
Определения классов могут расширять существующие определения классов, добавлять новые переменные и функции, а также изменять значения, определенные в родительском классе.
Вот класс, который расширяет предыдущий пример:
class Square extends Shape {
public $sideLength = 0;
public function __construct($sideLength) {
parent::__construct(4);
$this->sideLength = $sideLength;
}
public function perimeter() {
return $this->sides * $this->sideLength;
}
public function area() {
return $this->sideLength * $this->sideLength;
}
}
Класс Square содержит переменные и поведение как для класса Shape и для класса Square :
$mySquare = new Square(10);
print $mySquare->description()/ // A shape with 4 sides
print $mySquare->perimeter() // 40
print $mySquare->area() // 100
За последние 24 часа нас посетили 11447 программистов и 1168 роботов. Сейчас ищут 305 программистов …
Fatal error: Constant expression contains invalid operations in
Тема в разделе «PHP для новичков», создана пользователем Admiral_24, 22 ноя 2018.
-
Admiral_24
Новичок- С нами с:
- 18 ноя 2018
- Сообщения:
- 12
- Симпатии:
- 0
Fatal error: Constant expression contains invalid operations in
как передать конфиг?PHP:-
class DB
-
{
-
public function __construct($config) {
-
require_once «config.php»;
-
$config->db[‘db_host’];
-
$config->db[‘db_name’];
-
$config->db[‘db_user’];
-
$config->db[‘db_pass’];
-
}
-
}
-
public static $dsn = ‘mysql:dbname=’.$config[‘db_name’].‘;host=’.$config[‘db_host’];
-
public static $user = $config[‘db_user’];
-
public static $pass = $config[‘db_pass’];
-
/**
-
* Объект PDO.
-
*/
-
public static $dbh = null;
-
/**
-
* Statement Handle.
-
*/
-
public static $sth = null;
-
/**
-
* Выполняемый SQL запрос.
-
*/
-
public static $query = »;
-
/**
-
* Подключение к БД
-
*/
-
public static function getDbh()
-
{
-
if (!self::$dbh) {
-
try {
-
self::$dbh = new PDO(
-
self::$dsn,
-
self::$user,
-
self::$pass,
-
array(PDO::MYSQL_ATTR_INIT_COMMAND => «SET NAMES ‘utf8′»)
-
);
-
self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
-
} catch (PDOException $e) {
-
exit(‘Error connecting to database: ‘ . $e->getMessage());
-
}
-
}
-
return self::$dbh;
-
}
config.php
PHP:-
return [
-
‘db_host’=>‘localhost’;
-
‘db_name’=>‘test’;
-
‘db_user’=>‘root’;
-
‘db_pass’=>»;
#1
Admiral_24,22 ноя 2018
-
abrdabr
Новичок- С нами с:
- 28 янв 2017
- Сообщения:
- 774
- Симпатии:
- 65
номер строки с ошибкой?
#2
abrdabr,22 ноя 2018
-
Admiral_24
Новичок- С нами с:
- 18 ноя 2018
- Сообщения:
- 12
- Симпатии:
- 0
Ругается на public static $dsn=’mysql:dbname=’.$config[‘db_name’].’;host=’.$config[‘db_host’];
#3
Admiral_24,22 ноя 2018
-
nospiou
Старожил- С нами с:
- 4 фев 2018
- Сообщения:
- 3.400
- Симпатии:
- 510
@Admiral_24 это так не работает
PHP:-
public $dsn;
-
public $user;
-
….
-
public function __construct($config){
-
$this->dsn = ‘mysql:dbname=’.$config[‘db_name’].‘;host=’.$config[‘db_host’];
-
$this->user = …
-
}
#4
nospiou,22 ноя 2018
Admiral_24 нравится это.
-
abrdabr
Новичок- С нами с:
- 28 янв 2017
- Сообщения:
- 774
- Симпатии:
- 65
@Admiral_24 кавычки
public static $dsn = ‘mysql:dbname=’.(вар)$config[‘(пхп)db_name’].’;host=’.$config[‘db_host’];
юзай двойные чтоли#5
abrdabr,22 ноя 2018
-
Admiral_24
Новичок- С нами с:
- 18 ноя 2018
- Сообщения:
- 12
- Симпатии:
- 0
Fatal error: Uncaught Error: Access to undeclared static property: DB::$dsn in
PHP:-
class DB
-
{
-
public $dsn;
-
public $user;
-
public $pass;
-
public function __construct($config){
-
include «config.php»;
-
$this->dsn = ‘mysql:dbname=’.$config[‘db_name’].‘;host=’.$config[‘db_host’];
-
$this->user = $config[‘db_user’];
-
$this->pass = $config[‘db_pass’];
-
}
-
/**
-
* Объект PDO.
-
*/
-
public static $dbh = null;
-
/**
-
* Statement Handle.
-
*/
-
public static $sth = null;
-
/**
-
* Выполняемый SQL запрос.
-
*/
-
public static $query = »;
-
/**
-
* Подключение к БД
-
*/
-
public static function getDbh()
-
{
-
if (!self::$dbh) {
-
try {
-
self::$dbh = new PDO(
-
self::$dsn,
-
self::$user,
-
self::$pass,
-
array(PDO::MYSQL_ATTR_INIT_COMMAND => «SET NAMES ‘utf8′»)
-
);
-
self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
-
} catch (PDOException $e) {
-
exit(‘Error connecting to database: ‘ . $e->getMessage());
-
}
-
}
-
return self::$dbh;
-
}
#6
Admiral_24,22 ноя 2018
-
abrdabr
Новичок- С нами с:
- 28 янв 2017
- Сообщения:
- 774
- Симпатии:
- 65
$this->dsn = ‘mysql:dbname=’.$config[‘db_name’].’;host=’.$config[‘db_host’];
заменить на
$this->dsn = ‘mysql:dbname=’.$config[«db_name»].’;host=’.$config[«db_host»];кавычки
— Добавлено —
и закрывающую добавь
_host»]’;#7
abrdabr,22 ноя 2018
-
Admiral_24
Новичок- С нами с:
- 18 ноя 2018
- Сообщения:
- 12
- Симпатии:
- 0
причем здесь кавычки?
#8
Admiral_24,22 ноя 2018
-
abrdabr
Новичок- С нами с:
- 28 янв 2017
- Сообщения:
- 774
- Симпатии:
- 65
@Admiral_24 эммм ну к примеру потому что они необходимы
у тебя грубо написано так
$dsn=’var’secondvar;
то есть переменная синтаксически не верно задаётся#9
abrdabr,22 ноя 2018
-
nospiou
Старожил- С нами с:
- 4 фев 2018
- Сообщения:
- 3.400
- Симпатии:
- 510
construct это всегда new
$db = new DB($config)#10
nospiou,22 ноя 2018
Admiral_24 нравится это.
(Вы должны войти или зарегистрироваться, чтобы разместить сообщение.)
- Ваше имя или e-mail:
- У Вас уже есть учётная запись?
-
- Нет, зарегистрироваться сейчас.
- Да, мой пароль:
-
Забыли пароль?
-
Запомнить меня







































