PERF: PeriodArray._format_native_types
- [x] closes #23979 (Replace xxxx with the GitHub issue number)
- [ ] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
- [ ] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [ ] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
- [ ] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.

#23979 suggests implementing PeriodArray._format_native_types with self.to_timestamp()._format_native_types.  That _is_ faster than this, but this avoids copies, is robust to weekly freqs, and should further improve with #51459.

```
pi = pd.period_range("2016-01-01", periods=10**5, freq='H')
pa = pi._data
pa[4] = pd.NaT

%timeit pa._format_native_types()
246 ms ± 5.61 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)   # <- PR
411 ms ± 13.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)   # <- main

%timeit pa._format_native_types(date_format="%Y-%m-%d")
274 ms ± 8.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)   # <- PR
420 ms ± 13.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)   # <- main

In [18]: %timeit pa.to_timestamp()._format_native_types()
164 ms ± 3.43 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
```
Thanks @jbrockmendel 