매개 변수 형식 PHP 7에서 암시-개체의 배열입니다.
아맜으나 아무 옵션 그 함수를 정의한 사용자 개체의 배열 예제론 또는 반환이 있어야 한다 뭘 좀 놓쳤지?
다음 코드를 고려해 보자.
<?php
class User
{
protected $name;
protected $age;
/**
* User constructor.
*
* @param $name
*/
public function __construct(string $name, int $age)
{
$this->name = $name;
$this->age = $age;
}
/**
* @return mixed
*/
public function getName() : string
{
return $this->name;
}
public function getAge() : int
{
return $this->age;
}
}
function findUserByAge(int $age, array $users) : array
{
$result = [];
foreach ($users as $user) {
if ($user->getAge() == $age) {
if ($user->getName() == 'John') {
// complicated code here
$result[] = $user->getName(); // bug
} else {
$result[] = $user;
}
}
}
return $result;
}
$users = [
new User('John', 15),
new User('Daniel', 25),
new User('Michael', 15),
];
$matches = findUserByAge(15, $users);
foreach ($matches as $user) {
echo $user->getName() . ' '.$user->getAge() . "\n";
}
에는 함수 「PHP7」을?findUserByAge
용자 폭폭 ?려 려? ???나는 형식이라고 암시하며 그것이 가능해야 하지만 만약 이것이 포함되어 아니니까요 형식 개체의 배열이 아마도 PHP 7에 포함되지 않기 위해 암시에 대한 정보 찾지 못하고 추가되었으면, 널 때 형식이라고 암시하며 추가되었다 왜 그것이 포함되지는 않았다 어떤 단서를 가지고 있니 기대하느냐?
그것은 포함되지 않아요.
만약 그것이 포함되지 않을 때 형식이라고 암시하며 추가되었다 왜 그것이 포함되지는 않았으나, 뭐 단서를 가지고 있니?
현재 배열 시행에 따라, 그 배열 자체 형식 정보를 포함하는 런타임에, 모든 배열 요소 확인이 필요할 것이다.
이것은 사실 이미 PHP 5.6을 거부:제안된 바 있습니다. RFC"arrayof"-재미 있게 때문이 아니라 성능 문제가 바꾸어 판매했고neglible지만,이 아무런 합의에 정확히 어떻게 하는데 본격화하였다.또한 반대 이유는 비용이 스칼라 타입 힌트 없이 불완전하다고 있었다.온 토론에 흥미가 있다면, 메일링 리스트 문서 보관소에서 읽었어요.
내 짧은 생각으로 배열 형식 힌트 함께를 입력된 배열을 하고 나는 그들에게 실현되고 싶어요 대부분의 혜택을 제공할 것이다.
새로운 RFC그래서 이건 어쩌면에 대해 시간과 이 토론을 재개할.
부분 Workaround:
당신과 따라서 그 서명이 쓰힌트variadic 인수를 입력할 수 있다.
function findUserByAge(int $age, User ...$users) : array
사용방법:
findUserByAge(15, ...$userInput);
콜에서는 「」가 사용됩니다.$userInput
로 ".$users
각되었습니다.User
$userInput
반복기일 수도 있습니다.배열로 변환됩니다.
유감스럽게도 반환 유형에 대한 유사한 회피책은 없으며 마지막 인수에만 사용할 수 있습니다.
코드 베이스에는 컬렉션이라는 개념이 있습니다.이들은 ArrayObject를 기반으로 하는 TypedArray라는 클래스를 기반으로 합니다.
class ArrayObject extends \ArrayObject
{
/**
* Clone a collection by cloning all items.
*/
public function __clone()
{
foreach ($this as $key => $value) {
$this[$key] = is_object($value) ? clone $value : $value;
}
}
/**
* Inserting the provided element at the index. If index is negative, it will be calculated from the end of the Array Object
*
* @param int $index
* @param mixed $element
*/
public function insert(int $index, $element)
{
$data = $this->getArrayCopy();
if ($index < 0) {
$index = $this->count() + $index;
}
$data = array_merge(array_slice($data, 0, $index, true), [$element], array_slice($data, $index, null, true));
$this->exchangeArray($data);
}
/**
* Remove a portion of the array and optionally replace it with something else.
*
* @see array_splice()
*
* @param int $offset
* @param int|null $length
* @param null $replacement
*
* @return static
*/
public function splice(int $offset, int $length = null, $replacement = null)
{
$data = $this->getArrayCopy();
// A null $length AND a null $replacement is not the same as supplying null to the call.
if (is_null($length) && is_null($replacement)) {
$result = array_splice($data, $offset);
} else {
$result = array_splice($data, $offset, $length, $replacement);
}
$this->exchangeArray($data);
return new static($result);
}
/**
* Adding a new value at the beginning of the collection
*
* @param mixed $value
*
* @return int Returns the new number of elements in the Array
*/
public function unshift($value): int
{
$data = $this->getArrayCopy();
$result = array_unshift($data, $value);
$this->exchangeArray($data);
return $result;
}
/**
* Extract a slice of the array.
*
* @see array_slice()
*
* @param int $offset
* @param int|null $length
* @param bool $preserveKeys
*
* @return static
*/
public function slice(int $offset, int $length = null, bool $preserveKeys = false)
{
return new static(array_slice($this->getArrayCopy(), $offset, $length, $preserveKeys));
}
/**
* Sort an array.
*
* @see sort()
*
* @param int $sortFlags
*
* @return bool
*/
public function sort($sortFlags = SORT_REGULAR)
{
$data = $this->getArrayCopy();
$result = sort($data, $sortFlags);
$this->exchangeArray($data);
return $result;
}
/**
* Apply a user supplied function to every member of an array
*
* @see array_walk
*
* @param callable $callback
* @param mixed|null $userData
*
* @return bool Returns true on success, otherwise false
*
* @see array_walk()
*/
public function walk($callback, $userData = null)
{
$data = $this->getArrayCopy();
$result = array_walk($data, $callback, $userData);
$this->exchangeArray($data);
return $result;
}
/**
* Chunks the object into ArrayObject containing
*
* @param int $size
* @param bool $preserveKeys
*
* @return ArrayObject
*/
public function chunk(int $size, bool $preserveKeys = false): ArrayObject
{
$data = $this->getArrayCopy();
$result = array_chunk($data, $size, $preserveKeys);
return new ArrayObject($result);
}
/**
* @see array_column
*
* @param mixed $columnKey
*
* @return array
*/
public function column($columnKey): array
{
$data = $this->getArrayCopy();
$result = array_column($data, $columnKey);
return $result;
}
/**
* @param callable $mapper Will be called as $mapper(mixed $item)
*
* @return ArrayObject A collection of the results of $mapper(mixed $item)
*/
public function map(callable $mapper): ArrayObject
{
$data = $this->getArrayCopy();
$result = array_map($mapper, $data);
return new self($result);
}
/**
* Applies the callback function $callable to each item in the collection.
*
* @param callable $callable
*/
public function each(callable $callable)
{
foreach ($this as &$item) {
$callable($item);
}
unset($item);
}
/**
* Returns the item in the collection at $index.
*
* @param int $index
*
* @return mixed
*
* @throws InvalidArgumentException
* @throws OutOfRangeException
*/
public function at(int $index)
{
$this->validateIndex($index);
return $this[$index];
}
/**
* Validates a number to be used as an index
*
* @param int $index The number to be validated as an index
*
* @throws OutOfRangeException
* @throws InvalidArgumentException
*/
private function validateIndex(int $index)
{
$exists = $this->indexExists($index);
if (!$exists) {
throw new OutOfRangeException('Index out of bounds of collection');
}
}
/**
* Returns true if $index is within the collection's range and returns false
* if it is not.
*
* @param int $index
*
* @return bool
*
* @throws InvalidArgumentException
*/
public function indexExists(int $index)
{
if ($index < 0) {
throw new InvalidArgumentException('Index must be a non-negative integer');
}
return $index < $this->count();
}
/**
* Finding the first element in the Array, for which $callback returns true
*
* @param callable $callback
*
* @return mixed Element Found in the Array or null
*/
public function find(callable $callback)
{
foreach ($this as $element) {
if ($callback($element)) {
return $element;
}
}
return null;
}
/**
* Filtering the array by retrieving only these elements for which callback returns true
*
* @param callable $callback
* @param int $flag Use ARRAY_FILTER_USE_KEY to pass key as the only argument to $callback instead of value.
* Use ARRAY_FILTER_USE_BOTH pass both value and key as arguments to $callback instead of value.
*
* @return static
*
* @see array_filter
*/
public function filter(callable $callback, int $flag = 0)
{
$data = $this->getArrayCopy();
$result = array_filter($data, $callback, $flag);
return new static($result);
}
/**
* Reset the array pointer to the first element and return the element.
*
* @return mixed
*
* @throws \OutOfBoundsException
*/
public function first()
{
if ($this->count() === 0) {
throw new \OutOfBoundsException('Cannot get first element of empty Collection');
}
return reset($this);
}
/**
* Reset the array pointer to the last element and return the element.
*
* @return mixed
*
* @throws \OutOfBoundsException
*/
public function last()
{
if ($this->count() === 0) {
throw new \OutOfBoundsException('Cannot get last element of empty Collection');
}
return end($this);
}
/**
* Apply a user supplied function to every member of an array
*
* @see array_reverse
*
* @param bool $preserveKeys
*
* @return static
*/
public function reverse(bool $preserveKeys = false)
{
return new static(array_reverse($this->getArrayCopy(), $preserveKeys));
}
public function keys(): array
{
return array_keys($this->getArrayCopy());
}
/**
* Use a user supplied callback to reduce the array to a single member and return it.
*
* @param callable $callback
* @param mixed|null $initial
*
* @return mixed
*/
public function reduce(callable $callback, $initial = null)
{
return array_reduce($this->getArrayCopy(), $callback, $initial);
}
}
그리고.
/**
* Class TypedArray
*
* This is a typed array
*
* By enforcing the type, you can guarantee that the content is safe to simply iterate and call methods on.
*/
abstract class AbstractTypedArray extends ArrayObject
{
use TypeValidator;
/**
* Define the class that will be used for all items in the array.
* To be defined in each sub-class.
*/
const ARRAY_TYPE = null;
/**
* Array Type
*
* Once set, this ArrayObject will only accept instances of that type.
*
* @var string $arrayType
*/
private $arrayType = null;
/**
* Constructor
*
* Store the required array type prior to parental construction.
*
* @param mixed[] $input Any data to preset the array to.
* @param int $flags The flags to control the behaviour of the ArrayObject.
* @param string $iteratorClass Specify the class that will be used for iteration of the ArrayObject object. ArrayIterator is the default class used.
*
* @throws InvalidArgumentException
*/
public function __construct($input = [], $flags = 0, $iteratorClass = ArrayIterator::class)
{
// ARRAY_TYPE must be defined.
if (empty(static::ARRAY_TYPE)) {
throw new \RuntimeException(
sprintf(
'%s::ARRAY_TYPE must be set to an allowable type.',
get_called_class()
)
);
}
// Validate that the ARRAY_TYPE is appropriate.
try {
$this->arrayType = $this->determineType(static::ARRAY_TYPE);
} catch (\Collections\Exceptions\InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
// Validate that the input is an array or an object with an Traversable interface.
if (!(is_array($input) || (is_object($input) && in_array(Traversable::class, class_implements($input))))) {
throw new InvalidArgumentException('$input must be an array or an object that implements \Traversable.');
}
// Create an empty array.
parent::__construct([], $flags, $iteratorClass);
// Append each item so to validate it's type.
foreach ($input as $key => $value) {
$this[$key] = $value;
}
}
/**
* Adding a new value at the beginning of the collection
*
* @param mixed $value
*
* @return int Returns the new number of elements in the Array
*
* @throws InvalidArgumentException
*/
public function unshift($value): int
{
try {
$this->validateItem($value, $this->arrayType);
} catch (\Collections\Exceptions\InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
return parent::unshift($value);
}
/**
* Check the type and then store the value.
*
* @param mixed $offset The offset to store the value at or null to append the value.
* @param mixed $value The value to store.
*
* @throws InvalidArgumentException
*/
public function offsetSet($offset, $value)
{
try {
$this->validateItem($value, $this->arrayType);
} catch (\Collections\Exceptions\InvalidArgumentException $e) {
throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
}
parent::offsetSet($offset, $value);
}
/**
* Sort an array, taking into account objects being able to represent their sortable value.
*
* {@inheritdoc}
*/
public function sort($sortFlags = SORT_REGULAR)
{
if (!in_array(SortableInterface::class, class_implements($this->arrayType))) {
throw new \RuntimeException(
sprintf(
"Cannot sort an array of '%s' as that class does not implement '%s'.",
$this->arrayType,
SortableInterface::class
)
);
}
// Get the data from
$originalData = $this->getArrayCopy();
$sortableData = array_map(
function (SortableInterface $item) {
return $item->getSortValue();
},
$originalData
);
$result = asort($sortableData, $sortFlags);
$order = array_keys($sortableData);
uksort(
$originalData,
function ($key1, $key2) use ($order) {
return array_search($key1, $order) <=> array_search($key2, $order);
}
);
$this->exchangeArray($originalData);
return $result;
}
/**
* {@inheritdoc}
*/
public function filter(callable $callback, int $flag = 0)
{
if ($flag == ARRAY_FILTER_USE_KEY) {
throw new InvalidArgumentException('Cannot filter solely by key. Use ARRAY_FILTER_USE_BOTH and amend your callback to receive $value and $key.');
}
return parent::filter($callback, $flag);
}
}
사용 예
class PaymentChannelCollection extends AbstractTypedArray
{
const ARRAY_TYPE = PaymentChannel::class;
}
하다, 하다, 하다, 하다로 를 칠 수 되었습니다.PaymentChannelCollection
지불 채널
일부 코드는 네임스페이스에서 예외를 호출할 수 있습니다.danielgsims/php-collections에도 타입 검증기가 있다고 생각합니다(처음에는 이러한 컬렉션을 사용했지만 유연성에 문제가 있었습니다.우리에겐 좋지 않기 때문에, 어쨌든 한 번 봐 주세요).
어레이의 일반적인 유형 힌트에 대한 일반적인 답변을 드립니다.
나는 선택된 답을 변형했다.주요 차이점은 파라미터가 체크된 클래스의 많은 인스턴스가 아닌 배열이라는 것입니다.
/**
* @param $_foos Foo[]
*/
function doFoo(array $_foos)
{return (function(Foo ...$_foos){
// Do whatever you want with the $_foos array
})(...$_foos);}
약간 흐릿해 보이지만 이해하기 쉬워요.호출할 때마다 배열을 수동으로 풀지 않고 함수 내부의 닫힘이 호출되며 배열을 파라미터로 풀립니다.
function doFoo(array $_foos)
{
return (function(Foo ...$_foos){ // Closure
// Do whatever you want with the $_foos array
})(...$_foos); //Main function's parameter $_foos unpacked
}
Array Of Type 파라미터가 있는 다른 언어 기능과 마찬가지로 사용할 수 있기 때문에 매우 멋집니다.게다가 이 에러는, 다른 PHP 타입의 힌트 에러와 같은 방법으로 처리됩니다.또, 다른 프로그래머가 당신의 기능을 사용하고 있기 때문에, 항상 약간 허술한 느낌이 드는 어레이를 언팩할 필요가 있습니다.
프로그래밍에 대한 약간의 경험이 있어야 이 기능이 어떻게 작동하는지 이해할 수 있습니다.둘 이상의 매개변수가 필요한 경우 언제든지 폐쇄의 '사용' 섹션에 매개변수를 추가할 수 있습니다.
또한 문서 주석을 사용하여 유형 힌트를 표시할 수도 있습니다.
/**
* @param $_foos Foo[] <- An array of type Foo
*/
다음은 OO의 예입니다.
class Foo{}
class NotFoo{}
class Bar{
/**
* @param $_foos Foo[]
*/
public function doFoo(array $_foos, $_param2)
{return (function(Foo ...$_foos) use($_param2){
return $_param2;
})(...$_foos);}
}
$myBar = new Bar();
$arrayOfFoo = array(new Foo(), new Foo(), new Foo());
$notArrayOfFoo = array(new Foo(), new NotFoo(), new Foo());
echo $myBar->doFoo($arrayOfFoo, 'Success');
// Success
echo $myBar->doFoo($notArrayOfFoo, 'Success');
// Uncaught TypeError: Argument 2 passed to Bar::{closure}() must be an instance of Foo, instance of NotFoo given...
주의: 이것은 오브젝트 이외의 타입(int, string 등)에서도 동작합니다.
어레이에 혼재된 값을 포함할 수 있으므로 이는 불가능합니다.
그러기 위해서는 오브젝트/클래스를 사용해야 합니다.
이 문제가 꼭 필요한 경우 자체 목록 배열(개인/보호된 속성)을 관리하고 다른 값을 이 문제의 회피책으로 추가하는 것을 거부하는 클래스를 만들 수 있습니다.
그러나 책임 있는 프로그래머는 의도한 패턴을 깨는 일은 없습니다.특히, 코멘트를 올바르게 하고 있는 경우는 그렇습니다.어쨌든, 프로그램의 에러 발생시에 인식됩니다.
확장:
예를 들어 임의의 배열을 생성할 수 있습니다.
$myArray = array();
번호를 추가합니다.
$myArray[] = 1;
문자열:
$myArray[] = "abc123";
및 오브젝트
$myArray[] = new MyClass("some parameter", "and one more");
또, 심플한 어레이, 다차원 스택형 어레이, 및 패턴이 혼재하는 어소시에이션 어레이도 사용할 수 있습니다.
어레이의 포맷을 강요하는 표현으로 모든 버전을 동작시키는 파서/노테이션을 찾는 것은 매우 어렵습니다.
한편으론 멋지지만 다른 한편으론 기존 코드와 PHP가 제공하는 유연성에 매우 중요한 어레이 내에서 데이터를 혼합할 수 있는 능력을 잃게 됩니다.
PHP 7에서 놓치고 싶지 않은 기능이 혼재되어 있기 때문에 배열의 정확한 내용을 입력할 수 없습니다.
Steini가 대답한 것에 더해서.
클래스 오브젝트를 만들 수 있습니다.Niterator는 ObjectN을 관리하고 Iterator를 구현합니다.http://php.net/manual/en/class.iterator.php
methodN에서 classMethodM을 호출하여 채워진 개체를 반환합니다.그런 다음 Niterator는 이 데이터를 오브젝트를 예상하는 메서드O에 전달합니다.니테레이터:
public function methodO(ObjectNIterator $objectNCollection)
현시점에서는 오브젝트 배열의 함수 시그니처에 정의할 방법이 없습니다.그러나 기능 설명서에서 정의할 수 있습니다.혼합값을 전달해도 PHP 오류/경고는 생성되지 않지만 대부분의 IDE는 힌트를 제공합니다.다음은 예를 제시하겠습니다.
/**
* @param int $age
* @param User[] $users
* @return User[]
*/
function findUserByAge(int $age, array $users) : array {
$results = [];
//
//
return $result;
}
매우 간단한 접근법은 Forech, count, unset, indexing 등과 같은 PHP의 빌트인 함수와 함께 작동하는 자신만의 배열 유형을 만드는 것입니다.다음은 예를 제시하겠습니다.
class DataRowCollection implements \ArrayAccess, \Iterator, \Countable
{
private $rows = array();
private $idx = 0;
public function __construct()
{
}
// ArrayAccess interface
// Used when adding or updating an array value
public function offsetSet($offset, $value)
{
if ($offset === null)
{
$this->rows[] = $value;
}
else
{
$this->rows[$offset] = $value;
}
}
// Used when isset() is called
public function offsetExists($offset)
{
return isset($this->rows[$offset]);
}
// Used when unset() is called
public function offsetUnset($offset)
{
unset($this->rows[$offset]);
}
// Used to retrieve a value using indexing
public function offsetGet($offset)
{
return $this->rows[$offset];
}
// Iterator interface
public function rewind()
{
$this->idx = 0;
}
public function valid()
{
return $this->idx < count($this->rows);
}
public function current()
{
return $this->rows[$this->idx];
}
public function key()
{
return $this->idx;
}
public function next()
{
$this->idx++;
}
// Countable interface
public function count()
{
return count($this->rows);
}
}
사용 예:
$data = new DataRowCollection(); // = array();
$data[] = new DataRow("person");
$data[] = new DataRow("animal");
기존 어레이와 동일하게 작동하지만 원하는 대로 입력됩니다.매우 심플하고 효과적입니다.
언급URL : https://stackoverflow.com/questions/34273367/type-hinting-in-php-7-array-of-objects
'programing' 카테고리의 다른 글
Apache Commons는 왜 '२३?' 숫자를 고려합니까? (0) | 2022.09.22 |
---|---|
CDI와 EJB는 어떻게 비교됩니까?인터랙티브? (0) | 2022.09.22 |
SET NAME과 SET CHARSET의 차이점 (0) | 2022.09.22 |
데이터베이스에 색인을 추가하면 질의 결과 변경 (0) | 2022.09.21 |
양식 제출을 중지하는 JavaScript 코드 (0) | 2022.09.21 |