К сожалению, охват этого поля ввода в современных браузерах очень низок:
http://caniuse.com/#feat=input-number
Поэтому я рекомендую рассчитывать на резервную копию и полагаться на загруженный с тяжелой загрузкой ввод [type = text] для выполнения задания, пока это правило не будет принято.
До сих пор только Chrome, Safari и Opera имели аккуратную реализацию, но все остальные браузеры не работают. Некоторые из них даже не поддерживают десятичные знаки (например, BB10)!
Нет такой вещи, как определение свойства.
Вы можете объявить свойства только потому, что они являются контейнерами данных, зарезервированных в памяти при инициализации.
С другой стороны, функция может быть объявлена (типы, имя, параметры) без определения (тело функции отсутствует) и, таким образом, может быть сделана абстрактной.
«Абстрактный» указывает только на то, что что-то было объявлено, но не определено, и поэтому перед его использованием необходимо определить это, или оно станет бесполезным.
Как указано выше, такого точного определения не существует. Однако я использую этот простой обходной путь, чтобы заставить дочерний класс определить «абстрактное» свойство:
abstract class Father
{
public $name;
abstract protected function setName(); // now every child class must declare this
// function and thus declare the property
public function __construct()
{
$this->setName();
}
}
class Son extends Father
{
protected function setName()
{
$this->name = "son";
}
function __construct(){
parent::__construct();
}
}
PHP 7 значительно упрощает создание абстрактных «свойств». Как и выше, вы создадите их, создав абстрактные функции, но с помощью PHP 7 вы можете определить тип возвращаемого значения для этой функции, что значительно упрощает создание базового класса, который может расширять каждый.
<?php
abstract class FooBase {
abstract public function FooProp(): string;
abstract public function BarProp(): BarClass;
public function foo() {
return $this->FooProp();
}
public function bar() {
return $this->BarProp()->name();
}
}
class BarClass {
public function name() {
return 'Bar!';
}
}
class FooClass extends FooBase {
public function FooProp(): string {
return 'Foo!';
}
public function BarProp(): BarClass {
// This would not work:
// return 'not working';
// But this will!
return new BarClass();
}
}
$test = new FooClass();
echo $test->foo() . PHP_EOL;
echo $test->bar() . PHP_EOL;
Я задал себе тот же вопрос сегодня, и я хотел бы добавить свои два цента.
Причина, по которой мы хотели бы иметь свойства abstract
, заключается в том, чтобы убедиться, что подклассы определяют их и генерируют исключения, когда они этого не делают. В моем конкретном случае мне нужно было что-то, что могло бы работать с static
союзником.
В идеале я хотел бы что-то вроде этого:
abstract class A {
abstract protected static $prop;
}
class B extends A {
protected static $prop = 'B prop'; // $prop defined, B loads successfully
}
class C extends A {
// throws an exception when loading C for the first time because $prop
// is not defined.
}
Я закончил с этой реализацией
abstract class A
{
// no $prop definition in A!
public static final function getProp()
{
return static::$prop;
}
}
class B extends A
{
protected static $prop = 'B prop';
}
class C extends A
{
}
Как вы можете видеть, в A
я не определяю $prop
, но я использую его в static
геттере. Поэтому следующий код работает
B::getProp();
// => 'B prop'
$b = new B();
$b->getProp();
// => 'B prop'
В C
, с другой стороны, я не определяю $prop
, поэтому я получаю исключения:
C::getProp();
// => Exception!
$c = new C();
$c->getProp();
// => Exception!
Я должен вызовите метод getProp()
, чтобы получить исключение, и я не могу получить его при загрузке класса, но это довольно близко к желаемому поведению, по крайней мере, в моем случае.
Я определяю getProp()
как final
, чтобы избежать того, что какой-то умный парень (он же через 6 месяцев) испытывает искушение сделать
class D extends A {
public static function getProp() {
// really smart
}
}
D::getProp();
// => no exception...
Необходимость абстрактных свойств может указывать на проблемы проектирования. Хотя во многих ответах реализован тип шаблона шаблона , и он работает, он всегда выглядит несколько странно.
Давайте посмотрим на оригинальный пример:
abstract class Foo_Abstract {
abstract public $tablename;
}
class Foo extends Foo_Abstract {
//Foo must 'implement' $property
public $tablename = 'users';
}
Чтобы отметить что-то abstract
, нужно указать, что это необходимо. Итак, обязательное значение (в данном случае) является обязательной зависимостью, поэтому ее следует передать конструктору во время создания экземпляра :
class Table
{
private $name;
public function __construct(string $name)
{
$this->name = $name;
}
public function name(): string
{
return $this->name;
}
}
Тогда если вам действительно нужен более конкретный именованный класс, вы можете наследовать так:
final class UsersTable extends Table
{
public function __construct()
{
parent::__construct('users');
}
}
Это может быть полезно, если вы используете DI-контейнер и вам нужно передавать разные таблицы для разных объектов.